在學習SVG結構的時候,發現SVG結構可以通過以XML文件直接解析,所以就去了解了Tinyxml2庫的使用,相關教程也比較多。
個人感覺Tinyxml2庫比官方的XML解析庫更好用,這里做個技術總結,記錄Tinyxml2庫解析XML文件結構的簡單使用。
目錄導讀
- Tinyxml2庫 介紹(文言一心)
- 使用CMAKE 和 MSVC 2017 編譯 Tinyxml2庫
- QT 調用 **tinyxml2.lib** 解析XML
- 遍歷所有節點
- 將XML節點 加載到QTreeWidget 控件上
- 其他TinyXML2庫操作XML示例:
Tinyxml2庫 介紹(文言一心)
TinyXML-2 是一個簡單、小巧且功能強大的C++ XML解析庫,它是TinyXML的改進和擴展版本。該庫專注于易用性和性能,提供了對XML文檔的讀取、修改和創建功能。以下是TinyXML-2的主要特點:
- DOM風格API: TinyXML-2采用了Document Object Model(DOM)風格的API,允許開發者以樹形結構的方式操作XML數據。這意味著開發者可以輕松地遍歷、查詢和修改XML文檔。
- 輕量級: TinyXML-2的代碼量小,不依賴外部庫,因此非常適合嵌入式系統和移動設備。由于其小巧的體積和高效的實現,它在處理XML文檔的速度上表現出色。
- 易于使用: TinyXML-2的API設計直觀、簡潔,類和方法命名直觀(如XMLNode、XMLElement等),使得學習成本較低,易于理解和集成到項目中。
- 錯誤處理: TinyXML-2提供了一套全面的錯誤檢查機制。如果遇到無效的XML格式,它會拋出異常或返回錯誤代碼,幫助開發者快速定位問題。
支持解析和生成:TinyXML-2支持從字符串或文件中解析XML文檔,并且可以生成格式良好的XML文本。它能夠處理各種節點類型,如元素、屬性、文本、注釋等。 - 跨平臺: TinyXML-2完全基于標準C++編寫,可以在多種操作系統和編譯器環境下運行,包括Windows、Linux、Mac OS X等。
總的來說,TinyXML-2是一個功能強大、易于使用且跨平臺的C++ XML解析庫,適用于各種需要處理XML數據的場景。
Github: https://github.com/leethomason/tinyxml2
使用CMAKE 和 MSVC 2017 編譯 Tinyxml2庫
參考:xml開發筆記(一):tinyXml2庫介紹、編譯和工程模板
下載最新GitHub的項目通過CMAKE編譯:
Configure選擇MSCV2017編譯器和X64平臺:
直接Configure和Generate生成VS2017項目,可能是編譯器或版本文件沒有出現任何異常…
項目工程直接生成 tinyxml2.lib 沒有了dll文件。
xmltest.cpp 文件為調用示例,建議參考。
QT 調用 tinyxml2.lib 解析XML
將項目中的 tinyxml2.h 和 tinyxml2.cpp ,tinyxml2.lib 放在項目目錄下。
#include "tinyxml2/tinyxml2.h"using namespace tinyxml2;
using namespace std;//! tinyxml2.lib 絕對路徑
#pragma comment(lib,"E:\\data-bank\\Git\\Qt_XML_Lanalysis\\Qt_XML_Lanalysis\\XML_LAnalysis_UI\\tinyxml2\\tinyxml2.lib")
遍歷所有節點
加載XML文件遍歷所有節點,并輸出節點中的所有屬性值
參考:tinyxml/tinyxml2遍歷所有節點
#include <QDebug>
#include <QObject>
#include <QFileInfo>#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <wchar.h>void Lib_XmlReadWrite::GetEleValue(XMLElement * element)
{for (XMLElement* currentele = element->FirstChildElement(); currentele; currentele = currentele->NextSiblingElement()){XMLElement* tmpele = currentele;if (currentele->Name() != NULL||currentele->GetText() != NULL)qDebug() <<"-->" << currentele->Name() << ":" << currentele->GetText() ;if(tmpele->FirstAttribute()!=NULL){//! 輸出所有屬性值for (const XMLAttribute* var =tmpele->FirstAttribute(); var;var=var->Next()) {qDebug()<<"---->" <<var->Name()<<" : "<<var->Value();}}//! 有子節點繼續加載if (!tmpele->NoChildren())GetEleValue(tmpele);}
}void Lib_XmlReadWrite::LoadXML(QString xml)
{QFileInfo info("C:\\Users\\admin\\Desktop\\textxml\\text_xml5.xml");qDebug()<< "LoadXML -->"<<info.exists();XMLDocument doc;doc.LoadFile(info.absoluteFilePath().toStdString().c_str());qDebug()<<doc.ErrorIDToName(doc.ErrorID());qDebug()<< doc.FirstChild()->FirstChildElement()->Name();qDebug()<<doc.RootElement()->Name();qDebug()<<"-----------------------------------";GetEleValue(doc.RootElement());}
將XML節點 加載到QTreeWidget 控件上
通過 QTreeWidgetItem 結構將XML相關結構顯示到 QTreeWidget 控件上。
值得注意的是 如果一個文件有多個根節點可以通過
for (XMLElement* root = doc.RootElement(); root; root = root->NextSiblingElement())
遍歷所有根節點。
bool Lib_XmlReadWrite::LoadTreeWidget(QString xmlpath,QTreeWidgetItem* & item,QString& ErrorStr)
{//! 判斷文件是否存在!QFileInfo xmlInfo(xmlpath);if(!xmlInfo.exists()){ErrorStr=("文件["+QString(xmlpath)+"]不存在!");return false;}//! 加載xml格式文件doc.Clear();;doc.LoadFile(xmlInfo.absoluteFilePath().toStdString().c_str());if(doc.ErrorID()!=XML_SUCCESS){ErrorStr=("解析失敗:"+QString(doc.ErrorStr()));return false;}//! 添加文件根目錄item=new QTreeWidgetItem(QStringList()<<QString(xmlInfo.baseName())<<""<<xmlInfo.absoluteFilePath());//! 不一定只有一個節點for (XMLElement* root = doc.RootElement(); root; root = root->NextSiblingElement()){//! XML子節點QTreeWidgetItem* rootitem=new QTreeWidgetItem(QStringList()<<QString(root->Name())<<""<<root->GetText(),QTreeWidgetItem::UserType);RecursionElement(root,rootitem);item->addChild(rootitem);}return true;
}void Lib_XmlReadWrite::RecursionElement(XMLElement * element,QTreeWidgetItem* & item)
{//! 查找當前 element 子節點for (XMLElement* currentele = element->FirstChildElement(); currentele; currentele = currentele->NextSiblingElement()){XMLElement* tmpele = currentele;QTreeWidgetItem* childitem=new QTreeWidgetItem(QStringList()<<tmpele->Name()<<""<<tmpele->GetText());if(tmpele->FirstAttribute()!=NULL){//! 添加屬性值for (const XMLAttribute* var =tmpele->FirstAttribute(); var;var=var->Next()) {QTreeWidgetItem* attritem=new QTreeWidgetItem(QStringList()<<""<<var->Name()<<var->Value(),QTreeWidgetItem::UserType);attritem->setToolTip(2,var->Value());childitem->addChild(attritem);}}//! 查找 tmpele 子節點if (!tmpele->NoChildren())RecursionElement(tmpele,childitem);item->addChild(childitem);}
}/*!
//! 調用
void MainWindow::LoadXMLStructure(QString text)
{ui->treeWidget->clear();ui->treeWidget->setHeaderLabels(QStringList()<<"節點"<<"屬性"<<"業務值");ui->treeWidget->header()->setSectionResizeMode(QHeaderView::ResizeToContents);if(text=="")return;QString ErrorStr;QTreeWidgetItem* item;bool isbol=Lib_XmlReadWrite::LoadTreeWidget(text,item,ErrorStr);if(!isbol){qDebug()<<"[ErrorStr] "<<ErrorStr;ui->statusBar->showMessage(ErrorStr,0);}else{ui->treeWidget->addTopLevelItem(item);ui->treeWidget->expandAll();}
}
*/
效果:
其他TinyXML2庫操作XML示例:
TinyXML2庫解析xml感覺比Qt的QXmlStreamReader這種更好用,
但是不適合用來解析HTML文件,HTML文件中,像<link>這種節點會直接解析失敗。
參考:
- TinyXML2使用方法及示例
- 官方示例 xmltest.cpp 文件