QDomDocument 讀取和編輯xml檔案

Smalldy發表於2019-07-06

Qt中幾種操作xml的方式

  • 流方式
  • sax方式
  • dom方式

初學時,我常常採用流方式讀取xml,該方式簡單直觀,容易理解。之後遇到了需要修改xml並重新寫回的情況,流方式就顯得捉襟見肘了。

sax方式接觸不多,從來沒有在實際生產中使用過。

dom方式概念複雜,對於個人來說,文件也不是很清晰,導致我一直對這個方式不甚瞭解,最近下定決心好好研究一番,也算是大致清楚了箇中“套路”,在此記錄,以便今後查閱。

注意:如果你對QDomDocument沒有任何瞭解,則不適合閱讀此文章。如果你在使用QDomDocumentde的過程中產生了疑惑,則此文可能對你產生幫助。

如有疏漏,還望指正。

QDomNode ? QDomElemet? QDomAttr?QDomText?

初見QDomDocument時,我被這些東西搞得一頭霧水。
直到我看到了某部落格中這樣一段話:

QDom字首的都是代表節點型別。所以有,QDomElement代表一個Element節點,而QDomText代表一個Text節點。QDomNode類可以儲存任意型別的節點。如果想進一步處理一個節點,首先必須把它轉化為正確的資料型別。QDomNode呼叫toElement()以把它轉化成QDomElement,然後呼叫tagName()來獲得元素的標籤名稱。如果節點不是Element型別,那麼toElement()函式就返回一個空QDomElement物件和一個空標籤。1

我們對xml操作,無非對節點文字,節點屬性進行操作,因此,我著重在這個基礎上整理一下。

QDomNode 相容所有節點型別。
這裡只討論QDomNode為QDomElemet的情況;此時讀者心裡一驚,難道,還有不是的情況?當然有!

QDomNode QDomElemet

舉個簡單例子
你看!

  • 有如下xml
<bookstore category="xml">
    <book category="CHILDREN">
      <title>Harry Potter</title>
      <author>J K. Rowling</author>
      <year>2005</year>
      <price>29.99</price>
    </book>
    <!-- asdasd-->
    <book category="WEB">
      <title>Learning XML</title>
      <author>Erik T. Ray</author>
      <year>2003</year>
      <price>39.95</price>
    </book>
    <test>hello</test>
</bookstore>

有如下程式碼:

  • code 01
    QDomElement root = doc.documentElement();

    QDomNode node=  root.firstChild();
    qDebug() << root.attributeNode("category").value();
    while(!node.isNull())
    {
       qDebug() << "xx";
       node = node.nextSibling();
    }

結果會輸出幾個xx呢?

程式碼做出如下更改

  • code 02
    QDomElement root = doc.documentElement();

    QDomElement node=  root.firstChildElement();
    qDebug() << root.attributeNode("category").value();
    while(!node.isNull())
    {
       qDebug() << "xx";
       node = node.nextSiblingElement();
    }

結果會輸出幾個xx呢?

答案分別是4和3!:smirk: :smirk:

結論:註釋QDomNode而不是QDomElement

到這裡,大家應該就能明白兩者的區別了。也應該能讀懂上邊的

QDomNode呼叫toElement()以把它轉化成QDomElement,然後呼叫tagName()來獲得元素的標籤名稱。如果節點不是Element型別,那麼toElement()函式就返回一個空QDomElement物件和一個空標籤

[========]

QDomElemet 與 QDomAttr QDomText

經過上面的試驗,我們還可以得到另一個結論,那就是
屬性不是QDomELement子QDomELement
屬性不是QDomNode子QDomNode

還有一件事我們不知道,那就是QDomELement中的文字算是它的子QDomELement麼?

<bookstore category="xml">hello</bookstore>
  • code 03
    QDomElement ele=  root.firstChildElement();

    while(!ele.isNull())
    {
       qDebug() << "xx";
       ele = ele.nextSiblingElement();
    }

程式不會有任何輸出
文字不是QDomELement子QDomELement

  • code 04
    QDomNode node=  root.firstChild();

    while(!node.isNull())
    {
       qDebug() << "xx";
       node = node.nextSibling();
    }

程式將會輸出一個xx
文字QDomNode子QDomNode

瞭解了它們之間的聯絡之後,我們現在迫切的需要知道一個問題,既然文字和屬性都不是子QDomELement,如何獲取到文字和屬性呢?

讀寫xml

遍歷某QDomELement的 子QDomELement

  • 示例xml
<bookstore category="xml">
    <book category="CHILDREN">
      <title>Harry Potter</title>
      <author>J K. Rowling</author>
      <year>2005</year>
      <price>29.99</price>
    </book>
    <book category="WEB">
      <title>Learning XML</title>
      <author>Erik T. Ray</author>
      <year>2003</year>
      <price>39.95</price>
    </book>
    <test>hello</test>
</bookstore>
  • code 05 遍歷
    QDomDocument doc = QDomDocument();
    QFile file("./test.xml");
    file.open(QFile::ReadWrite);
    doc.setContent(&file);

    QDomElement root = doc.documentElement();

    QDomElement ele=  root.firstChildElement();

    while(!ele.isNull())
    {
       //do something

       ele = ele.nextSiblingElement();
    }

doc.documentElement()獲取最頂級的QDomDocument,接下來的迴圈遍歷了它所有的QDomDocument,對於它的子QDomDocument,同樣可以使用以上方法。
如果一個QDomDocumentfirstChildElement()返回的QDomElement為空(ele.isNull() 為 true),則說明他沒有子QDomElement,也就意味著他是xml的最底層了,接下來介紹獲取文字和屬性的方法。

  • code 06 讀取
    QDomDocument doc = QDomDocument();
    QFile file("./test.xml");
    file.open(QFile::ReadWrite);
    doc.setContent(&file);

    QDomElement root = doc.documentElement();

    QDomElement ele=  root.firstChildElement();

    qDebug() << root.attributeNode("category").nodeValue();

    while(!ele.isNull())
    {
        //此處可以有多種判定方法,此處只是採用了子元素為空判定
        //實際生產中你很可能不需要這樣判斷,根據xml結構直接判定元素名稱即可
        //如 if(ele.tagName() == "xxxx")
        if(ele.firstChildElement().isNull())
        {
            qDebug() << ele.tagName();
            qDebug() << ele.text();

            //文字是ele的子QDomNode,而不是ele本身! 所以這樣不會輸出任何東西!
            qDebug() << ele.toText().nodeValue();
            //如果真的需要轉化為QDomText
            QDomNode node = ele.firstChild();
            while (!node.isNull()) {
                if(node.isText())
                {
                    qDebug() << node.toText().nodeValue();
                }
                node = node.nextSibling();
            }

        }
       ele = ele.nextSiblingElement();
    }

輸出

"xml"
"test"
"hello"
""
"hello"

修改很簡單,只需要將上邊的nodeValue函式改為setNodeValue即可。記得要寫回檔案改動才會生效哦(詳情請檢視save方法的幫助文件)。

除此之外QDomDocument還提供了替換節點的方法,自行探索。

轉載請註明出處

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">





相關文章