文章目錄
-
-
- XML檔案簡介
- XML檔案格式
-
- 基本格式
- 注意事項
- Qt環境下XML解析示例
-
- 示例1解析
- 示例2解析
-
XML檔案簡介
xml,一般指可擴充标記語言,是一種用于标記電子檔案使其具有結構性的标記語言。早在1998年,W3C就釋出了XML1.0規範,使用它來簡化Internet的文檔資訊傳輸。XML有兩個先驅:SGML和HTML,這兩個語言都是非常成功的标記語言,但是都有一些與生俱來的缺陷。XML正是為了解決它們的不足而誕生的。
簡單的說,就是按照一定的格式,把資料表示出來。和JSON格式很像,關于JSON資料格式及其解析可以參考以下文章:
- JSON格式簡介
- 使用cJSON庫解析JSON
- 使用cJSON庫建構JSON字元串
- Qt平台下使用QJson解析和建構JSON字元串
- Keil環境下Jansson解析庫的使用——基于STM32F103
XML檔案格式
XML是樹形結構,通常由根節點+子節點組成,或者叫根元素+子元素組成。
基本格式
XML檔案第一行必須是聲明語句:
聲明語句之後,是根元素,XML必須有而且隻能有1個根元素,名稱任意:
<?xml version="1.0" encoding="UTF-8"?>
<root>
</root>
XML語句格式:元素+屬性
<元素名 屬性名=“屬性值”>
</元素名>
<元素名 屬性名1=“屬性值1” 屬性名2=“屬性值2”>
</元素名>
//當元素不包含子元素時,可以簡寫為以下格式
<元素名 屬性名=“屬性值”/>
<元素名 屬性名1=“屬性值1” 屬性名2=“屬性值2”/>
示例:
//元素不包含子元素
<user blog="www.wangchaochao.top" wechat="mcu149"/>
<user csdn_id="whik1194" wechat="mcu149"/>
也可以寫成
<user blog="www.wangchaochao.top" wechat="mcu149">
</user>
<user csdn_id="whik1194" wechat="mcu149">
</user>
元素中包含子元素
<user csdn_id="whik1194">
<home>https://blog.csdn.net/whik1194</home>
<wechat>mcu149</wechat>
<blog>www.wangchaochao.top</blog>
</user>
示例1,全部采用元素的方式:
<?xml version="1.0" encoding="utf-8"?>
<root>
<csdn id="whik1194">
<home>https://blog.csdn.net/whik1194</home>
<follower>709</follower>
</csdn>
<zhihu id="wangchao149">
<home>https://www.zhihu.com/people/wangchao149</home>
<follower>4961</follower>
</zhihu>
</root>
示例2,采用元素+屬性的方式:
<?xml version="1.0" encoding="utf-8"?>
<root>
<csdn id="whik1194" home="https://blog.csdn.net/whik1194" follower="709"/>
<zhihu id="wangchao149" home="https://www.zhihu.com/people/wangchao149" follower="4961"></zhihu>
</root>
注意事項
- XML區分大小寫,而且第一個字元不能是數字或下劃線
- 标記必須成對出現,有一個開始标記,就必須有一個結束标記,否則認為文法錯誤
- XML規定,所有屬性值必須加引号,可以是單引号,或雙引号,建議統一使用雙引号
Qt環境下XML解析示例
Qt環境下解析XML主要有以下3種方式:
- QXmlStreamReader
- DOM(Document Object Model)
- SAX(Simple API for XML)
優缺點對比參考:
- 從代碼行數來看,采用DOM和QXmlSimpleReader的方式,代碼行數比較少,而QXmlStreamReader代碼行數較多。
- 從代碼邏輯分析來看,采用DOM方式最容易了解,采用QXmlStreamReader的方式稍微難了解一些,而采用QXmlSimpleReader由于使用了較多的回調,引入了大量的類資料成員,使得代碼會很難了解。
- 從記憶體占用來看,DOM的方式會耗費最多的記憶體,因為需要一次性将所有的内容建構成樹,DOM和QXmlSimpleReader對記憶體要求都較低。
- 從運作時間消耗來看,DOM的消耗,可能會稍微大一些,因為DOM正常要經曆2次的周遊,一次周遊建構樹,一次周遊,建構自己需要的資料。而QXmlSimpleReader和QXmlStreamReader正常隻需要周遊一次。
- 從處理異常來看,DOM和QXmlStreamReader應該會更容易一些,因為不涉及回調函數,但是對于xml來說,很多時候主要确認内容正确與否,如果錯誤就退出,檢視xml中的錯誤。當然,這個也是比較重要的項。
對于我來說,因為大多數情況下,解析的xml不是很大,而且基本隻涉及加載過程中,是以使用DOM的情況比較多。如果xml比較大,或者調用比較頻繁,可以考慮使用QXmlStreamReader的方式。
至于生成 XML 文檔,Qt 同樣提供了三種方式:
- QXmlStreamWriter,與QXmlStreamReader相對應;
- DOM 方式,首先在記憶體中生成 DOM 樹,然後将 DOM 樹寫入檔案。不過,除非我們程式的資料結構中本來就維護着一個 DOM 樹,否則,臨時生成樹再寫入肯定比較麻煩;
- 純手工生成 XML 文檔,顯然,這是最複雜的一種方式。
本文隻講解基于DOM如何解析XML。
首先,Qt需要添加XML支援,在.pro檔案中添加一行:
QT += xml
并将XML檔案添加到資源路徑,或者不添加直接通過檔案名通路。
頭檔案包含:
#include <QDomDocument>
#include <QDomElement>
基本操作,檔案的打開:
bool MainWindow::parseXML(QString fileName)
{
//step1.XML檔案打開
if(fileName.isEmpty())
{
qDebug() << "fileName is empty";
return false;
}
QFile file(fileName);
if(!file.open(QFile::ReadOnly | QFile::Text))
{
QMessageBox::warning(this, "Warning", fileName + "\n" + file.errorString());
return false;
}
qDebug() << "file open success: " << fileName;
// .........
}
然後加載到DOM中,并驗證XML文法格式,如果文法格式不正确,錯誤資訊儲存在errStr中。
//step2.XML檔案加載到DOM中,并驗證文法格式
QDomDocument docXML;
QString errStr;
int row, column;
if(!docXML.setContent(&file, false, &errStr, &row, &column))
{
QMessageBox::warning(this, "Warning", \
fileName + "\nsetContent failed at line: " + QString::number(row, 10) + "\n" + errStr);
file.close();
return false;
}
qDebug() << "docXML setContent success";
file.close();
以上兩個步驟是所有XML檔案解析都必須進行的操作。下面來根據不同的XML檔案格式來進行解析。
示例1解析
XML檔案内容
文本内容:
<?xml version="1.0" encoding="utf-8"?>
<root>
<csdn id="whik1194">
<home>https://blog.csdn.net/whik1194</home>
<follower>709</follower>
</csdn>
<zhihu id="wangchao149">
<home>https://www.zhihu.com/people/wangchao149</home>
<follower>4961</follower>
</zhihu>
</root>
解析函數:
bool MainWindow::parseXML(QString fileName)
{
//step1.XML檔案打開
//step2.XML檔案加載到DOM中,并驗證文法格式
//step3.XML解析
QDomElement xmlRoot = docXML.documentElement();
//擷取根節點名稱
if (xmlRoot.tagName() != "root")
{
qDebug() << "root tagName is not match";
return false;
}
//子節點清單
QDomNodeList nodeList = xmlRoot.childNodes();
qDebug() << "nodeList size: " << nodeList.size();
//csdn
for(int i = 0; i < nodeList.size(); i++)
{
QDomNode node = nodeList.at(i);
QDomElement element = node.toElement();
QString tagName = element.tagName(); //"csdn" or "zhihu"
QString id = element.attribute("id");
qDebug() << tagName << id;
//擷取所有的子節點: home & follower
QDomNodeList eleNodeList= element.childNodes();
for(int j = 0; j < eleNodeList.size(); j++)
{
QDomElement ele = eleNodeList.at(j).toElement();
QString eleTagName = ele.tagName(); //"home" or "follower"
//"https://blog.csdn.net/whik1194" or "709"
//"https://www.zhihu.com/people/wangchao149" or "4961"
QString eleTagValue = ele.text();
qDebug() << eleTagName << eleTagValue;
}
qDebug() << "-----------";
}
return true;
}
運作結果:
file open success: ":/xml/demo.xml"
docXML setContent success
nodeList size: 2
"csdn" "whik1194"
"home" "https://blog.csdn.net/whik1194"
"follower" "709"
-----------
"zhihu" "wangchao149"
"home" "https://www.zhihu.com/people/wangchao149"
"follower" "4961"
-----------
示例2解析
XML檔案内容:
文本檔案内容:
<?xml version="1.0" encoding="utf-8"?>
<root>
<csdn id="whik1194" home="https://blog.csdn.net/whik1194" follower="709"/>
<zhihu id="wangchao149" home="https://www.zhihu.com/people/wangchao149" follower="4961"></zhihu>
</root>
解析函數:
bool MainWindow::parseXML(QString fileName)
{
//step1.XML檔案打開
//step2.XML檔案加載到DOM中,并驗證文法格式
//step3.XML解析
QDomElement xmlRoot = docXML.documentElement();
//擷取根節點名稱
if (xmlRoot.tagName() != "root")
{
qDebug() << "root tagName is not match";
return false;
}
//子節點清單
QDomNodeList nodeList = xmlRoot.childNodes();
qDebug() << "nodeList size: " << nodeList.size();
//csdn
for(int i = 0; i < nodeList.size(); i++)
{
QDomNode node = nodeList.at(i);
QDomElement element = node.toElement();
QString tagName = element.tagName(); //"csdn" or "zhihu"
QString id = element.attribute("id");
QString home = element.attribute("home");
QString follower = element.attribute("follower");
qDebug() << tagName << id << home << follower;
qDebug() << "-----------";
}
return true;
}
運作結果:
file open success: ":/xml/demo.xml"
docXML setContent success
nodeList size: 2
"csdn" "whik1194" "https://blog.csdn.net/whik1194" "709"
"zhihu" "wangchao149" "https://www.zhihu.com/people/wangchao149" "4961"