C++ XML 库 TinyXML2 的基本使用

C++ XML 库 TinyXML2 的基本使用0.前言TinyXML-2是一个简单,小型,高效的C++XML解析器,可以轻松集成到其他程序中,直接引用源文件的话只需要包含两个文件(h和cpp,此外还有个测试文件里面带有demo)。TinyXML-2解析XML文档,并以此为基础构建可读取,修改和保存的文档对象模型(DOM)。文档说,在解释XML时仅使用UTF-8,假定所有XML为UTF-8(看了下使用MSVC编译器时生成的XML文件文本编码使用的本地编码)。该库还支持打印到文件或内存,使用XMLPr

大家好,又见面了,我是你们的朋友全栈君。

0.前言

TinyXML-2 是一个简单,小型,高效的 C ++ XML 解析器,可以轻松集成到其他程序中,直接引用源文件的话只需要包含两个文件(h 和 cpp,此外还有个测试文件里面带有 demo)。

TinyXML-2 解析 XML 文档,并以此为基础构建可读取,修改和保存的文档对象模型(DOM)。文档说,在解释 XML 时仅使用 UTF-8 ,假定所有 XML 为 UTF-8 (看了下使用 MSVC 编译器时生成的 XML 文件文本编码使用的本地编码)。该库还支持打印到文件或内存,使用 XMLPrinter 类。

GitHub 链接:https://github.com/leethomason/tinyxml2

(在线文档我的网访问不了,但是下载库 GitHub 上的项目后带有离线文档,用谷歌浏览器在线翻译即可)

1.基本使用

引入头文件:

#include "tinyxml2.h"

//tinyxml2的类在tinyxml2命名空间
using namespace tinyxml2;

使用 XMLDocument 加载和保存 XML 文件:

//构造一个xml文档类
XMLDocument doc;
//读取文件
//从磁盘加载XML文件。成功返回XML_SUCCESS(0),或者返回errorID。
XMLError error = doc.LoadFile(xmlPath);
//也可以解析字符串
//XMLError tinyxml2::XMLDocument::Parse(const char *xml,size_t nBytes = static_cast<size_t>(-1));
if (error != XMLError::XML_SUCCESS)
	return;
//存储到文件,参数2 compact紧凑默认false
doc.SaveFile(xmlPath);

可以借助 XMLDocument 生成节点(元素、属性、文本、注释等),也可以直接 new 生成对象,但还要使用 Insert 方法才能插入到结构中:

//元素
XMLElement * tinyxml2::XMLDocument::NewElement (const char *name)
//注释
XMLComment * tinyxml2::XMLDocument::NewComment (const char *comment)
//文本
XMLText * tinyxml2::XMLDocument::NewText (const char *text) 
//XML文件头描述
XMLDeclaration * tinyxml2::XMLDocument::NewDeclaration (const char *text=0)
//未知类型
XMLUnknown * tinyxml2::XMLDocument::NewUnknown (const char *text)

//插入到末尾
XMLNode * tinyxml2::XMLNode::InsertEndChild (XMLNode *addThis)
//插入到开头
XMLNode * tinyxml2::XMLNode::InsertFirstChild (XMLNode *addThis)
//插入到节点的下一个位置
XMLNode * tinyxml2::XMLNode::InsertAfterChild (XMLNode *afterThis, XMLNode *addThis)

删除子节点:

//删除所有子节点
void tinyxml2::XMLNode::DeleteChildren ()
//删除指定子节点
void tinyxml2::XMLNode::DeleteChild (XMLNode *node)

对于查找,可通过父子兄弟节点进行遍历:

//是否不包含子节点
bool tinyxml2::XMLNode::NoChildren () const
//第一个子节点
const XMLNode * tinyxml2::XMLNode::FirstChild () const
//第一个子元素 
const XMLElement * tinyxml2::XMLNode::FirstChildElement (const char *name=0) const
//最后一个子节点
const XMLNode * tinyxml2::XMLNode::LastChild () const
//最后一个子元素
const XMLElement * tinyxml2::XMLNode::LastChildElement (const char *name=0) const
//上一个兄弟节点 
const XMLNode * tinyxml2::XMLNode::PreviousSibling () const
//上一个兄弟元素 
const XMLElement * tinyxml2::XMLNode::PreviousSiblingElement (const char *name=0) const
//下一个兄弟节点
const XMLNode * tinyxml2::XMLNode::NextSibling () const
//下一个兄弟元素
const XMLElement * tinyxml2::XMLNode::NextSiblingElement (const char *name=0) const

如果要遍历整个文档,可从 XMLDocument 开始遍历,XXXChild + XXXSibling 遍历所有的子节点和兄弟节点。

2.简单的示例

第一生成的 XML 结构如下:

<?xml version="1.0" encoding="UTF-8"?>
<ElementA Level="A" Value="1992">ElementA text<!--ElementA comment--><ElementB Level="B">ElementB text<!--ElementB comment--></ElementB>
</ElementA>

<!--My TinyXml2 Test... ...-->Some Test
<!Unknown>

第二次生成的 XML 结构如下:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
    <GroupA Type="A">
        <Name>中文<Content>111111</Content>
        </Name>
        <Name>English<Content>222222</Content>
        </Name>
        <Name>123<Content>333333</Content>
        </Name>
    </GroupA>
    <GroupB Type="B"/>
    <GroupC Type="C"/>
</Root>

完整代码:

#include <iostream>
#include <string>
#include "tinyxml2.h"
//tinyxml2的类在tinyxml2命名空间
using namespace tinyxml2;
//测试生成xml
void create_xml(const char* xmlPath);
//测试解析xml
void parse_xml(const char* xmlPath);
//遍历xml node
void traversal_node(XMLNode* node);
//遍历xml element
void traversal_element(XMLNode* node, int level);
//生成预定格式xml
void create_xml2(const char* xmlPath);
//解析预定义格式xml
void parse_xml2(const char* xmlPath);
int main()
{
const char* path = "./test.xml";
create_xml(path);
parse_xml(path);
const char* path2 = "./test2.xml";
create_xml2(path2);
parse_xml2(path2);
system("pause");
return 0;
}
void create_xml(const char* xmlPath)
{
std::cout << "\ncreate_xml:" << xmlPath << std::endl;
//【】构造一个xml文档类
XMLDocument doc;
//【】操作文档相关接口
//创建与此文档关联的新声明。对象的内存由文档管理。
//如果'text'参数为null,则使用标准声明:
//<?xml version="1.0" encoding="UTF-8"?>
XMLDeclaration* declaration = doc.NewDeclaration();
//创建与此文档关联的新元素。元素的内存由文档管理。
XMLElement* element = doc.NewElement("ElementA");
//创建与此文档关联的新注释。注释的内存由文档管理。
XMLComment* comment = doc.NewComment("My TinyXml2 Test... ...");
//创建与此文档关联的新文本。文本的存储由文档管理。
XMLText* text = doc.NewText("Some Test");
//创建与此文档关联的新的未知节点。对象的内存由文档管理。
XMLUnknown* unknown = doc.NewUnknown("Unknown");
//【】创建了节点还要插入文档中
//添加一个子节点作为最后一个(右)子节点。如果子节点已经是文档的一部分,则将其从其旧位置移至新位置。
//XMLNode* tinyxml2::XMLNode::InsertEndChild(XMLNode * addThis);
//添加一个子节点作为第一个(左)子节点。如果子节点已经是文档的一部分,则将其从其旧位置移至新位置。
//XMLNode* tinyxml2::XMLNode::InsertFirstChild(XMLNode* addThis);
//在指定的子节点之后添加一个节点。如果子节点已经是文档的一部分,则将其从其旧位置移至新位置。
//XMLNode* tinyxml2::XMLNode::InsertAfterChild(XMLNode * afterThis, XMLNode * addThis);
doc.InsertFirstChild(declaration);
doc.InsertAfterChild(declaration, element);
doc.InsertEndChild(comment);
doc.InsertEndChild(text);
doc.InsertEndChild(unknown);
//【】操作节点相关接口
//将命名属性设置为对应类型的value
element->SetAttribute("Level", "A");
element->SetAttribute("Value", 1992);
//设置文本
element->SetText("ElementA text");
//注释
element->InsertNewComment("ElementA comment");
//添加子节点,接口已经带insert功能了
XMLElement* sub_element = element->InsertNewChildElement("ElementB");
sub_element->SetAttribute("Level", "B");
sub_element->SetText("ElementB text");
sub_element->InsertNewComment("ElementB comment");
//【】存储到文件,参数2 compact紧凑默认false
//结构写的不规范,感觉应该拿一个根节点把那些注释,文本包起来
//不然解析的时候没法访问啊
doc.SaveFile(xmlPath);
}
void parse_xml(const char* xmlPath)
{
std::cout << "\nparse_xml:" << xmlPath << std::endl;
//【】构造一个xml文档类
XMLDocument doc;
//【】读取文件
//从磁盘加载XML文件。成功返回XML_SUCCESS(0),或者返回errorID。
XMLError error = doc.LoadFile(xmlPath);
//也可以解析字符串
//从字符串解析XML文件。成功返回XML_SUCCESS(0),或者返回errorID。
//XMLError tinyxml2::XMLDocument::Parse(const char *xml,size_t nBytes = static_cast<size_t>(-1));
if (error != XMLError::XML_SUCCESS)
return;
//注意,实际解析时返回的指针记得判空,不然遇到解析失败异常就遭了
//【】解析根元素
//返回DOM的根元素。等效于FirstChildElement。要获取第一个节点,请使用FirstChild。
XMLElement* root = doc.RootElement();
std::cout << "RootElement name:" << root->Name() << std::endl;
//获取第一个子元素,或者选择具有指定名称的第一个子元素。
XMLElement* first = doc.FirstChildElement("ElementA");
//给定一个属性名称,Attribute返回该名称的属性的值;如果不存在,则返回null。
std::cout << "FirstChildElement Attr Level:" << first->Attribute("Level") << std::endl;
std::cout << "FirstChildElement Attr Value:" << first->Attribute("Value") << std::endl;
//如果'this'的第一个Child是XMLText,则GetText返回Text节点的字符串,否则返回null。
std::cout << "FirstChildElement Text:" << first->GetText() << std::endl;
//【】解析子元素
XMLElement* sub = root->FirstChildElement("ElementB");
std::cout << "SubElement Attr Level:" << sub->Attribute("Level") << std::endl;
std::cout << "SubElement Text:" << sub->GetText() << std::endl;
//【】
//可使用FirstChild+NextSibling遍历子节点
std::cout << "\ntraversal_xml:" << std::endl;
traversal_node(&doc);
//或者FirstChildElement+NextSiblingElement遍历子元素
std::cout << "\ntraversal_element:" << std::endl;
traversal_element(&doc, 0);
}
void traversal_node(XMLNode* node)
{
if (!node)
return;
for (XMLNode* current = node->FirstChild(); current != nullptr; current = current->NextSibling())
{
XMLNode* temp = current;
if (temp->Value() != nullptr)
std::cout << temp->Value() << std::endl;
if (!temp->NoChildren())
traversal_node(temp);
}
}
void traversal_element(XMLNode* node, int level)
{
if (!node)
return;
for (XMLElement* current = node->FirstChildElement(); current != nullptr; current = current->NextSiblingElement())
{
XMLElement* temp = current;
//这里我使用点号来表示层级缩进
std::cout << std::string(level * 5, '.') << temp->Name() << std::endl;
if (temp->GetText() != nullptr)
std::cout << std::string(level * 5, '.') << "> Text" << ":" << temp->GetText() << std::endl;
const XMLAttribute* attr = temp->FirstAttribute();
if (attr != nullptr)
std::cout << std::string(level * 5, '.') << "> Attr" << ":" << attr->Value() << std::endl;
if (temp->FirstChildElement() != nullptr)
traversal_element(temp, level + 1);
}
}
void create_xml2(const char* xmlPath)
{
std::cout << "\ncreate_xml2:" << xmlPath << std::endl;
//【】构造一个xml文档类
XMLDocument doc;
//【】构建我们的xml数据结构
XMLDeclaration* declaration = doc.NewDeclaration();
doc.InsertFirstChild(declaration);
//创建与此文档关联的新元素。元素的内存由文档管理。
XMLElement* root = doc.NewElement("Root");
doc.InsertEndChild(root);
//子节点
XMLElement* group_a = root->InsertNewChildElement("GroupA");
group_a->SetAttribute("Type", "A");
XMLElement* a_1 = group_a->InsertNewChildElement("Name");
a_1->SetText("中文");
XMLElement* a_1_sub = a_1->InsertNewChildElement("Content");
a_1_sub->SetText("111111");
XMLElement* a_2 = group_a->InsertNewChildElement("Name");
a_2->SetText("English");
XMLElement* a_2_sub = a_2->InsertNewChildElement("Content");
a_2_sub->SetText("222222");
XMLElement* a_3 = group_a->InsertNewChildElement("Name");
a_3->SetText("123");
XMLElement* a_3_sub = a_3->InsertNewChildElement("Content");
a_3_sub->SetText("333333");
XMLElement* group_b = root->InsertNewChildElement("GroupB");
group_b->SetAttribute("Type", "B");
XMLElement* group_c = root->InsertNewChildElement("GroupC");
group_c->SetAttribute("Type", "C");
//【】存储到文件,参数2 compact紧凑默认false
doc.SaveFile(xmlPath);
}
void parse_xml2(const char* xmlPath)
{
std::cout << "\nparse_xml2:" << xmlPath << std::endl;
//【】构造一个xml文档类
XMLDocument doc;
//【】读取文件
//从磁盘加载XML文件。成功返回XML_SUCCESS(0),或者返回errorID。
XMLError error = doc.LoadFile(xmlPath);
//也可以解析字符串
//从字符串解析XML文件。成功返回XML_SUCCESS(0),或者返回errorID。
//XMLError tinyxml2::XMLDocument::Parse(const char *xml,size_t nBytes = static_cast<size_t>(-1));
if (error != XMLError::XML_SUCCESS)
return;
//注意,实际解析时返回的指针记得判空,不然遇到解析失败异常就遭了
//【】解析根节点
//返回DOM的根元素。等效于FirstChildElement。要获取第一个节点,请使用FirstChild。
XMLElement* root = doc.RootElement();
//【】查找
XMLElement* find_ele = root->FirstChildElement("GroupA");
if (find_ele) {
std::cout << find_ele->Name() << std::endl;
const XMLAttribute* attr = find_ele->FindAttribute("Type");
if (attr) {
std::cout << attr->Name() << ":" << attr->Value() << std::endl;
}
XMLElement* find_sub = find_ele->FirstChildElement("Name");
if (find_sub && find_sub->GetText()) {
std::cout << find_sub->GetText() << std::endl;
}
}
//【】遍历
std::cout << "\ntraversal_element:" << std::endl;
traversal_element(&doc, 0);
}

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/138983.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 免备案使用国内服务器_国外服务器国内域名要不要备案

    免备案使用国内服务器_国外服务器国内域名要不要备案关于免备案这个问题,我首先说明一下,我不是在提倡大家域名不要备案,这只是一项技术并不是用来给大家滥用的,希望大家能够明白!众所周知,要想使用国内服务器或者主机是是必须要通过工信局的ICP备案的,但是也有的伙伴怕麻烦或者通过不了,这里我教下大家这个使用CDN做到免备案,其实要做到绕过国内服务器域名备案的方法目前小编知道的有两种,一种是利用反向代理、一种就是利用CDN,当然了,你有更多方法愿意分享出来的,可以在评论下方提出。今天,我们就着重讲利用CDN绕备案吧首先,我们要准备好工具,网站、服务器、域

  • MDT 2013 Update 1 Preview 部署 Windows 10之概览

    MDT 2013 Update 1 Preview 部署 Windows 10之概览

  • 免费且好玩的API接口

    免费且好玩的API接口

    2021年11月11日
  • Android文件系统的结构及目录用途、操作方法 整理「建议收藏」

    Android文件系统的结构及目录用途、操作方法 整理「建议收藏」1、android文件系统的结构android源码编译后得到system.img,ramdisk.img,userdata.img映像文件。其中,ramdisk.img是emulator的文件系统,system.img包括了主要的包、库等文件,userdata.img包括了一些用户数据,emulator加载这3个映像文件后,会把system和userdata分别加载到ram

    2022年10月15日
  • nonlocal怎么用_result的用法

    nonlocal怎么用_result的用法这个nonlocal是py3.x中才有的关键词第一种情况,不使用nonlocal的情况:#-*-encoding:utf-8-*-importsysreload(sys)sys.setdefaultencoding(‘utf-8’)deftest():x=1print(“test=”+str(x))#####################

  • Istio组件日志设置[通俗易懂]

    1.istio-pilot日志级别编辑istio-system.deployment.istio-pilot,修改args中–log_output_level=default:指定日志级别2.istio-policy日志级别设置同istio-pilot3.istio-proxy(envoy)日志级别设置进入istio-proxy容器中,通过如下命令进行设置:curl-…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号