QT開發(四十二)——DOM方式解析XML

QT開發(四十二)——DOM方式解析XML

一、DOM簡介

1DOM簡介

    DOMDocument Object Model的簡寫,即XML文檔對象模型,是由W3C提出的一種處理XML文檔的標準接口

    DOM 一次性讀入整個XML文檔,在內存中構造爲一棵樹DOM樹)將XML文件表示成一棵樹,便於隨機訪問其中的節點,但消耗內存相對多一些。能夠在這棵樹上進行導航,比如移動到下一節點或者返回上一節點,也可以對這棵樹進行修改,或者是直接將這顆樹保存爲硬盤上的一個 XML 文件。

2XML DOM節點

    XML 文檔中的每個成分都是一個節點,整個文檔是一個文檔節點,每個XML 標籤是一個元素節點,包含在XML元素中的文本是文本節點, 每一個XML屬性是一個屬性節點,註釋屬於註釋節點。

    QT中使用QDomDocument來表示XML文檔QDomElement表示XML文檔的元素,QDomProcessingInstruction表示XML處理指令,QDomAttr表示元素的屬性,QDomText表示XML文檔中的文本數據。所有的DOM節點如處理指令、元素、屬性和文本數據等,都使用QDomNode來表示,然後使用對應的 isProcessingInstruction()、isElement()、isAttr()和isText()等函數來判斷是否是該類型的節點,如果是,那麼就可以使用toProcessingInstruction()、toElement()、toAttr()和toText()等函數轉換爲具體類型的節點。

    文本數據總是存儲在文本節點中,元素節點的文本數據是存儲在文本節點中的。

二、QDomDocument

1QDomDocument簡介

    QDomDocument類用於顯示XML文檔,是文檔樹的根節點,提供了對文檔數據的主要訪問。由於元素、文本節點、註釋、說明等不能在文檔外部,QDomDocument包含了創建這些對象的工廠函數。

    需要解析的XML文檔在內部顯示爲一棵被QDOM其它類訪問的對象樹。所有的QDOM類只能引用對象樹中的對象。一旦或是QDomDocument根節點被刪除,DOM樹中的所有內部對象將被刪除。

    元素、文本節點等的創建由QDomDocument類提供的工廠函數完成。使用默認的QDOM類的構造函數只能得到一個不能操作、插入文檔的空對象。

    QDomDocument類有多個用於創建文檔數據的函數,如createElementcreateTextNodecreateCommentcreateCDATASectioncreateProcessingInstructioncreateAttributecreateEntityReference。這些函數中的一些支持命名空間的版本。createDocumentFragment函數爲了持有文檔中的部分內容,對於操作複雜文檔是很有用的。

    設置文檔的整體內容使用setContent()函數。setContent函數通過XML文檔和創建顯示文檔的DOM樹來解析文檔。

    對於較大的XML文檔,DOM樹會佔用較大的內存空間。對於較大的XML文檔,使用QXmlStreamReaderQXmlQuery會使更好的解決方案。

2QDomDocument成員函數

QDomDocument::QDomDocument(const QString &name)

QDomDocument::QDomDocument(const QDomDocumentType &doctype)

QDomDocument::QDomDocument(const QDomDocument &x)

構造函數

QDomAttr QDomDocument::createAttribute(const QString &name)

創建一個能夠插入到元素的名爲name的新屬性

QDomAttr QDomDocument::createAttributeNS(const QString &nsURI, const QString &qName)

創建一個能夠插入到元素的支持命名空間的新屬性,名字爲qName,命名空間爲nsURI

QDomCDATASection QDomDocument::createCDATASection(const QString &value)

創建一個能插入文檔的值爲value的新CDATA

QDomComment QDomDocument::createComment(const QString &value)

創建一個能插入文檔的值爲value的新註釋

QDomDocumentFragment QDomDocument::createDocumentFragment()

創建一個持有文檔部分內容的文檔段

QDomElement QDomDocument::createElement(const QString &tagName)

創建一個能插入DOM樹的名爲tagName的新元素

QDomElement QDomDocument::createElementNS(const QString &nsURI, const QString &qName)

創建一個能插入DOM樹的支持命名空間的名爲qName的新元素,命名空間爲nsURI

QDomEntityReference QDomDocument::createEntityReference(const QString &name)

創建一個能插入文檔的名爲name的新實體引用

QDomProcessingInstruction QDomDocument::createProcessingInstruction(const QString &target, const QString &data)

創建一個能插入文檔的新的說明,設置說明的目標爲target,數據爲data

QDomText QDomDocument::createTextNode(const QString &value)

創建一個能插入文檔樹的值爲value的新文本節點

QDomDocumentType QDomDocument::doctype() const

返回文檔的文檔類型

QDomElement QDomDocument::documentElement() const

返回文檔的根元素

QDomElement QDomDocument::elementById(const QString &elementId)

返回ID爲elementId的元素

QDomNodeList QDomDocument::elementsByTagName(const QString &tagname) const

返回包含tagname文檔的所有元素的節點鏈表

QDomNodeList QDomDocument::elementsByTagNameNS(const QString &nsURI, const QString &localName)

返回包含本地名爲localName、命名空間爲nsURI的文檔的所有元素的節點鏈表

QDomImplementation QDomDocument::implementation() const

返回QDomImplementation對象

QDomNode QDomDocument::importNode(const QDomNode &importedNode, bool deep)

從另一個文檔導入importedNode節點到文檔,如果deeptrue,導入importedNode節點的子樹,否則導入importedNode節點。

QDomNode::NodeType QDomDocument::nodeType() const

返回節點類型

bool QDomDocument::setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg = Q_NULLPTR, int *errorLine = Q_NULLPTR, int *errorColumn = Q_NULLPTR)

從字節數組數據data解析XML文檔,並設置爲文檔的內容

bool QDomDocument::setContent(const QString &text, bool namespaceProcessing, QString *errorMsg = Q_NULLPTR, int *errorLine = Q_NULLPTR, int *errorColumn = Q_NULLPTR)

從字符串text中讀取XML文檔,如果成功解析了內容,返回true

bool QDomDocument::setContent(QIODevice *dev, bool namespaceProcessing, QString *errorMsg = Q_NULLPTR, int *errorLine = Q_NULLPTR, int *errorColumn = Q_NULLPTR)

從設備dev中讀取XML文檔,如果成功解析了內容,返回true

bool QDomDocument::setContent(QXmlInputSource *source, bool namespaceProcessing, QString *errorMsg = Q_NULLPTR, int *errorLine = Q_NULLPTR, int *errorColumn = Q_NULLPTR)

QXmlInputSource中讀取XML文檔,如果成功解析了內容,返回true

QByteArray QDomDocument::toByteArray(int indent = 1) const

返回解析後的文檔的文本內容的UTF-8格式的字節數組數據

QString QDomDocument::toString(int indent = 1) const

返回解析後的文檔的文本內容

三、QDomElement

1、QDomElement簡介

    QDomElement表示DOM樹中的一個元素節點。元素有一個標籤名和0個或多個屬性。

2、QDomElement成員函數

QString QDomElement::attribute(const QString &name, const QString &defValue = QString()) const

返回元素的名字爲name的屬性,如果不存在,返回defValue默認值

QDomAttr QDomElement::attributeNode(const QString &name)

返回元素中名字爲name的屬性的QDomAttr對象

QDomNamedNodeMap QDomElement::attributes() const

返回元素中所有屬性的通過名字訪問屬性節點的集合

QDomNodeList QDomElement::elementsByTagName(const QString &tagname) const

返回元素名爲tagname的元素的所有子節點的前序遍歷的節點鏈表

bool QDomElement::hasAttribute(const QString &name) const

如果元素中有名字爲name的屬性,返回true

void QDomElement::removeAttribute(const QString &name)

刪除元素中名字爲name的屬性

void QDomElement::setAttribute(const QString &name, const QString &value)

在元素中添加一個名字爲name,值爲value的屬性,如果已經存在,使用value替換值

void QDomElement::setTagName(const QString &name)

設置元素的標籤名爲name

QString QDomElement::tagName() const

返回元素的標籤名

QString QDomElement::text() const

返回元素的文本

四、QDomAttr

QDomAttr表示元素的屬性

QString QDomAttr::name() const

返回屬性的名字

QDomElement QDomAttr::ownerElement() const

返回屬性所屬的元素節點

void QDomAttr::setValue(const QString &v)

設置屬性的值爲v

bool QDomAttr::specified() const

如果屬性已經由用戶設置,返回true

QString QDomAttr::value() const

返回屬性的值

五、DOM方式操作XML文件

DOM方式解析XML文件先打開XML文件,將XML文件整體加載到內存中建立DOM樹,對於XML文檔的任何操作在內存中的DOM樹直接操作,最後保存時將DOM樹的所有節點寫回XML文檔。需要注意的是,通常打開XML文件,將XML文件加載到內存中建立DOM樹後,XML文件就可以關閉了。如果要保存改變後的XML文檔內容,需要在保存時以清空文件的方式打開XML文件,將改變後DOM樹的所有節點寫入XML文件即可。

1、讀取XML文件

<?xml version="1.0" encoding="UTF-8"?>

<library>

    <book time="2013/6/13" id="1">

        <title>C++ primer</title>

        <author>Stanley Lippman</author>

    </book>

    <book time="2007/5/25" id="2">

        <title>Thinking in Java</title>

        <author>Bruce Eckel</author>

    </book>

</library>

讀取的XML文件的代碼如下:

    

//打開或創建文件
    QFile file("test.xml");
    if(!file.open(QFile::ReadOnly))
        return;
 
    QDomDocument doc;
    //設置test.xml到文檔
    if(!doc.setContent(&file))
    {
        file.close();
        return;
    }
    file.close();
 
    //返回根節點
    QDomElement root=doc.documentElement();
    qDebug()<<root.nodeName();
    //獲得第一個子節點
    QDomNode node=root.firstChild();
    while(!node.isNull())  //如果節點不空
    {
        if(node.isElement()) //如果節點是元素
        {
            //轉換爲元素
            QDomElement e=node.toElement();
            qDebug()<<e.tagName()<<" "<<e.attribute("id")<<" "<<e.attribute("time");
            QDomNodeList list=e.childNodes();
            for(int i=0;i<list.count();i++)
            {
                QDomNode n=list.at(i);
                if(node.isElement())
                    qDebug()<<n.nodeName()<<":"<<n.toElement().text();
            }
        }
        //下一個兄弟節點
        node=node.nextSibling();
    }

2、XML文件

   

 //打開或創建文件
    QFile file("test.xml");
    //QIODevice::Truncate表示清空原來的內容
    if(!file.open(QFile::WriteOnly|QFile::Truncate))
        return;
 
    QDomDocument doc;
    //添加處理命令
    QDomProcessingInstruction instruction;
    instruction=doc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
    doc.appendChild(instruction);
    //添加根節點
    QDomElement root=doc.createElement("library");
    doc.appendChild(root);
    //添加第一個子節點及其子元素
    QDomElement book=doc.createElement("book");
    //方式一:創建屬性  其中鍵值對的值可以是各種類型
    book.setAttribute("id",1);
    //方式二:創建屬性 值必須是字符串
    QDomAttr time=doc.createAttribute("time");
    time.setValue("2013/6/13");
    book.setAttributeNode(time);
    QDomElement title=doc.createElement("title"); //創建子元素
    QDomText text; //設置括號標籤中間的值
    text=doc.createTextNode("C++ primer");
    book.appendChild(title);
    title.appendChild(text);
    QDomElement author=doc.createElement("author"); //創建子元素
    text=doc.createTextNode("Stanley Lippman");
    author.appendChild(text);
    book.appendChild(author);
    //添加節點book做爲根節點的子節點
    root.appendChild(book);
 
    //添加第二個子節點及其子元素
    book=doc.createElement("book");
    book.setAttribute("id",2);
    time=doc.createAttribute("time");
    time.setValue("2007/5/25");
    book.setAttributeNode(time);
    title=doc.createElement("title");
    text=doc.createTextNode("Thinking in Java");
    book.appendChild(title);
    title.appendChild(text);
    author=doc.createElement("author");
    text=doc.createTextNode("Bruce Eckel");
    author.appendChild(text);
    book.appendChild(author);
    root.appendChild(book);
 
    //輸出到文件
    QTextStream out_stream(&file);
    doc.save(out_stream,4); //縮進4格
    file.close();

寫入XML文件如下:

<?xml version="1.0" encoding="UTF-8"?>

<library>

    <book time="2013/6/13" id="1">

        <title>C++ primer</title>

        <author>Stanley Lippman</author>

    </book>

    <book time="2007/5/25" id="2">

        <title>Thinking in Java</title>

        <author>Bruce Eckel</author>

    </book>

</library>

3、增加XML文件內容

   

 //打開文件
    QFile file("test.xml");
    if(!file.open(QFile::ReadOnly))
        return;
 
    //增加一個一級子節點以及元素
    QDomDocument doc;
    if(!doc.setContent(&file))
    {
        file.close();
        return;
    }
    file.close();
 
    QDomElement root=doc.documentElement();
    QDomElement book=doc.createElement("book");
    book.setAttribute("id",3);
    book.setAttribute("time","1813/1/27");
    QDomElement title=doc.createElement("title");
    QDomText text;
    text=doc.createTextNode("Pride and Prejudice");
    title.appendChild(text);
    book.appendChild(title);
    QDomElement author=doc.createElement("author");
    text=doc.createTextNode("Jane Austen");
    author.appendChild(text);
    book.appendChild(author);
    root.appendChild(book);
 
    if(!file.open(QFile::WriteOnly|QFile::Truncate))
        return;
    //輸出到文件
    QTextStream out_stream(&file);
    doc.save(out_stream,4); //縮進4格
    file.close();

4、刪除XML文件

    

//打開文件
    QFile file("test.xml");
    if(!file.open(QFile::ReadOnly))
        return;
 
    //刪除一個一級子節點及其元素,外層節點刪除內層節點於此相同
    QDomDocument doc;
    if(!doc.setContent(&file))
    {
        file.close();
        return;
    }
    file.close();
 
    QDomElement root=doc.documentElement();
    QDomNodeList list=doc.elementsByTagName("book"); //由標籤名定位
    for(int i=0;i<list.count();i++)
    {
        QDomElement e=list.at(i).toElement();
        if(e.attribute("time")=="2007/5/25")  
            root.removeChild(list.at(i));
    }
 
    if(!file.open(QFile::WriteOnly|QFile::Truncate))
        return;
    //輸出到文件
    QTextStream out_stream(&file);
    doc.save(out_stream,4); //縮進4格
    file.close();

5、修改XML文件

    

//打開文件
    QFile file("test.xml");
    if(!file.open(QFile::ReadOnly))
        return;
 
    //更新一個標籤項,如果知道xml的結構,直接定位到那個標籤上定點更新
    //或者用遍歷的方法去匹配tagname或者attribut,value來更新
    QDomDocument doc;
    if(!doc.setContent(&file))
    {
        file.close();
        return;
    }
    file.close();
 
    QDomElement root=doc.documentElement();
    QDomNodeList list=root.elementsByTagName("book");
    QDomNode node=list.at(list.size()-1).firstChild();
    QDomNode oldnode=node.firstChild();
    node.firstChild().setNodeValue("Emma");
    QDomNode newnode=node.firstChild();
    node.replaceChild(newnode,oldnode);
 
    if(!file.open(QFile::WriteOnly|QFile::Truncate))
        return;
    //輸出到文件
    QTextStream out_stream(&file);
    doc.save(out_stream,4); //縮進4格
    file.close();

 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章