在学习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 文件