Qt---Xml文件解析

本文咱們經過一個讀取Xml文件的小例子來學習QXmlStreamReader。css

Xml 簡介

Xml的全稱是可擴展標記語言(EXtensible Markup Language),同HTML同樣是一種標記語言。可是與HTML不一樣,XML:html

  • 被設計爲具備自我描述性
  • 沒有預約義標籤,須要使用者自行定義。
  • 設計宗旨是傳輸數據,而非顯示數據(HTML)。大多數Android App開發都用Xml文件做爲界面開發的數據載體。

QXmlStreamReader 簡介

QXmlStreamReader is a faster and more convenient replacement for Qt's own SAX parser (see QXmlSimpleReader).git

官方宣稱這是一個比Qt的SAX(Simple API for XML)解析器更快、更方便的替代,也就是說建議你優先使用它來解析Xml文件。github

QXmlStreamReader和SAX的工做原理相似,都是以Token爲單位對Xml文件進行讀取解析。使用QXmlStreamReader基本上有兩種模式:函數

mode-pic

這兩種方法的區別就是處理單位的不一樣,分別以Token、Element爲單位:前者粒度更細,把控能夠更精準,但相對的須要花更多的功夫在細節處理上;後者只關注元素,對於簡單的處理使用起來很方便。在QXmlStreamReader中,讀取Token須要調用QXmlStreamReader::readNext()函數,該函數返回讀取到的Token,不一樣的Token類型須要調用不一樣的函數來獲取相關的內容,詳細內容參見Qt官方連接;而讀取元素則是調用QXmlStreamReader::readNextStartElement()函數,注意此函數簡單地區別頭元素和尾元素,若是是頭元素則返回true,不然(尾元素或出錯)返回false。學習

解析Xml 元素

Xml中的元素與HTML同樣:編碼

<title>Colombia Earthquake</title>

這就是一個title元素,包含一些文本內容。咱們經過調用QXmlStreamReader::readNextStartElement()來讀取它,當讀取的是一個元素的時候,QXmlStreamReader::name()函數返回元素的名字,QXmlStreamReader::readElementText()返回元素內的文本。設計

解析Xml 文檔元素

<?xml version="1.0" encoding="ISO-8859-1"?>

Xml文檔元素包含常見的xml版本、編碼、獨立文檔(standalone)等元數據,這些屬性分別對應QXmlStreamReader的documentVersion()documentEncoding()isStandaloneDocument()等函數,可是在調用這些函數前咱們須要先調用readNext()函數讓解析器先去讀取這個特殊元素。code

void MainWindow::readDocumentElement()
{
    m_xmlReader.readNext();
    if (m_xmlReader.isStartDocument()) {
        auto item = new QTreeWidgetItem(
                    QStringList("Document Element"));
        item->setText(1, "xml version:" + m_xmlReader.documentVersion().toString() +
                    "    encoding:" + m_xmlReader.documentEncoding().toString() +
                    "    is standalone:" + (m_xmlReader.isStandaloneDocument() ? QString("true") : QString("false")));
        item->setBackgroundColor(1, QColor(Qt::green));
        m_treeWidget.addTopLevelItem(item);
    }
}

解析Xml CDATA

CDATA(Character Data) 表明字符數據,這個區段中的文本不會被Xml 解析器解析,而是原樣保留輸出。CDATA區段以<![CDATA[開始,以]]>結束,這兩個標記符號中間的文本能夠是]]>之外的任何字符。CDATA常常被用來存儲那些包含特殊字符(Xml關鍵字或者保留字符)的文本,以下:xml

<![CDATA[ This is a <CDATA> section text! ]]>

<在Xml是特殊字符,用來標識元素的開始,若是上面這段文字不寫在CDATA區段中, 這塊內容就會被解析爲頭元素;經過CDATA區段,Xml 解析器會把這塊內容原樣輸出。使用QXmlStreamReader,咱們的代碼相似以下:

void MainWindow::readCDATA()
{
    while (!m_xmlReader.isCDATA()) {
        m_xmlReader.readNext();
    }
    auto item = new QTreeWidgetItem(QStringList("[CDATA]"));
    item->setText(1, m_xmlReader.text().toString());
    item->setBackgroundColor(1, QColor(Qt::cyan));
    m_treeWidget.addTopLevelItem(item);
}

由於CDATA區段不是元素,所以咱們須要調用QXmlStreamReader::readNext()函數。

解析Xml DTD

文檔類型定義(DTD)可定義合法的XML文檔構建模塊。它使用一系列合法的元素來定義文檔的結構。

簡而言之,DTD是用來描述Xml文檔的結構的,語法以下:

<!DOCTYPE 根元素 [元素聲明]>

例以下面這個DTD:

<!DOCTYPE note [
    <!ELEMENT note (to,from,heading,body)>
    <!ELEMENT to      (#PCDATA)>
    <!ELEMENT from    (#PCDATA)>
    <!ELEMENT heading (#PCDATA)>
    <!ELEMENT body    (#PCDATA)>
]>
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

該DTD 解釋以下:

!DOCTYPE note (第1行)定義此文檔是 note 類型的文檔。
!ELEMENT note (第2行)定義 note 元素有四個元素:"to、from、heading,、body"
!ELEMENT to (第3行)定義 to 元素爲 "#PCDATA" 類型
!ELEMENT from (第4行)定義 from 元素爲 "#PCDATA" 類型
!ELEMENT heading (第5行)定義 heading 元素爲 "#PCDATA" 類型
!ELEMENT body (第6行)定義 body 元素爲 "#PCDATA" 類型

用QXmlStreamReader解析DTD也很是方便,方法與解析CDATA同樣,只是換了個判斷函數:

while (!m_xmlReader.isDTD()) {
    m_xmlReader.readNext();
}
auto item = new QTreeWidgetItem(QStringList("[DTD]"));
item->setText(1, m_xmlReader.text().toString());
item->setBackgroundColor(1, QColor(Qt::darkMagenta));
m_treeWidget.addTopLevelItem(item);

解析Xml 註釋

Xml 的註釋也與HTML相同,<!-- XXXXXXXXXXXXXXXXXXX -->,代碼與上一小節基本同樣,只是判斷處改用了QXmlStreamReader::isComment()

while (!m_xmlReader.isComment()) {
    m_xmlReader.readNext();
}
...

解析Xml Processing Instruction

XMl PI(Processing Instruction) 處理指令使用這種格式<?PITarget PIContent?>,前一部分是Target,後一部分是Content。Processing Instruction用來告訴Xml應用程序進行一些Xml之外的操做,例如在有一些應用中,Xml文件須要包含一些CSS文件用以應用樣式來渲染自身:

<?xml-stylesheet type="text/css" href="tutorials.css"?>

在QXmlStreamReader中,好像緊貼<?的被識別位Target,後面的內容都被認爲是Content:

while (!m_xmlReader.isProcessingInstruction()) {
    m_xmlReader.readNext();
}
auto item = new QTreeWidgetItem(QStringList("[ProcessingInstruction]"));
item->setText(1, "target: " + m_xmlReader.processingInstructionTarget().toString() +
                 "    content: " + m_xmlReader.processingInstructionData().toString());
item->setBackgroundColor(1, QColor(Qt::yellow));
m_treeWidget.addTopLevelItem(item);

獲取PI相關內容須要分別調用QXmlStreamReader::processingInstructionTarget()QXmlStreamReader::processingInstructionData()

示例運行結果

由於Xml的元素是自定義的,這就意味着每每不一樣的Xml內部的元素結構都不同,不一樣的約定格式須要編寫不一樣的邏輯代碼處理。這個示例咱們用QTreeWidget來展現解析出來的結構和內容:

result-link

完整代碼見連接

相關文章
相關標籤/搜索