XML文件解析库 - tinyxml2 的基础使用方法笔记

发布时间 2023-10-30 19:50:07作者: 它的一天

感谢MenAngel大佬的分享:TinyXml2的详解及使用 - MenAngel - 博客园 (cnblogs.com)
以下笔记主要参考的就是大佬的这篇文章。

一、我的笔记

1.使用须知

进行项目时需要tinyxml2.htinyxml2.cpp参与进来,xmltest.cpp是官方测试(学习)文件。开源地址

编译命令 g++ -g -std=c++17 -LD:\workspace\C++\XMLFileModifier main.cpp tinyxml2.cpp -o test

-g:这是用于生成调试信息的选项。当你在编译时包含 -g 选项时,编译器将生成与源代码行号、变量名等相关的调试信息,以便你可以在调试时查看程序的内部状态。这对于在调试器中跟踪和修复代码中的问题非常有用。(编译好的可执行文件体积会变大)
-L:这是用于指定库文件搜索路径的选项。在命令中,-LD\wor... 指定了编译器应该在 D\wor... 目录中搜索库文件(找tinyxml2.h文件)。

2.常用操作

1)生成XML文件

#include "tinyxml2.h"
#include <iostream>

using namespace tinyxml2;

int main() {
    // 创建XML文档
    XMLDocument doc; // XMLDocument 文档节点

    // 添加XML声明节点
    XMLDeclaration* decl = doc.NewDeclaration("xml version=\"1.0\" encoding=\"UTF-8\"");  // XMLDeclaration
    doc.InsertFirstChild(decl);  // InsertFirstChild是用于向一个元素节点(XMLElement)添加子节点的函数,插入为父元素节点的第一个子节点

    // 创建根元素节点
    XMLElement* root = doc.NewElement("root");  // XMLElement 元素节点
    doc.InsertEndChild(root); // InsertEndChild:这个函数将一个节点插入为父元素节点的最后一个子节点

    // 创建元素节点 "person" 并添加到根元素
    XMLElement* personElement = doc.NewElement("person");
    root->InsertEndChild(personElement);
    // 创建属性节点 "name" 并添加到 "person" 元素
    personElement->SetAttribute("name", "John");  //  属性节点
    // 创建文本节点并添加文本内容到 "person" 元素
    XMLText* textElement = doc.NewText("This is some text.");  // XMLText 文本节点
    personElement->InsertEndChild(textElement);
    // personElement->SetText("This is some text.aaaa");  // 也可以这样添加文本节点

    // 创建第二个元素节点 "person" 并添加到根元素
    XMLElement* personElement2 = doc.NewElement("person");
    root->InsertEndChild(personElement2);
    personElement2->SetAttribute("name", "anna");

    // 创建第三个元素节点 "sonPerson" 并添加到第二个person元素
    XMLElement* son = doc.NewElement("sonPerson");
    personElement2->InsertEndChild(son);
    son->SetAttribute("name","2333");
    XMLText* te = doc.NewText("51555");
    son->InsertEndChild(te);

    // 保存XML文档到文件
    doc.SaveFile("example.xml");

    std::cout << "XML document created and saved to 'example.xml'" << std::endl;

    return 0;
}

这是生成的XML文件

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <person name="John">This is some text.</person>
    <person name="anna">
        <sonPerson name="2333">51555</sonPerson>
    </person>
</root>

2)读取&修改XML文件

#include "tinyxml2.h"
#include <iostream>

using namespace tinyxml2;

int main() {
    // 创建XML文档
    XMLDocument doc;

    // 加载XML文件
    XMLError loadResult = doc.LoadFile("D:\\Temp\\WorkSpace\\C++\\example.xml");
    // 检查加载操作是否成功
    if (loadResult == XML_SUCCESS) {
        std::cout << "XML document loaded successfully." << std::endl;
    }else{
        // 如果加载操作失败,输出错误信息
        std::cout << "Failed to load XML document. Error code: " << loadResult << std::endl;
        return -1;
    }

    // 获取根元素
    // FirstChildElement("root") 是 tinyXML2 中的一个函数调用,查找当前元素的子元素中第一个具有指定名称的元素,如果有多个同名的子元素,将返回第一个匹配的元素;一个都找不到就返回空指针(nullptr)。
    // NextSiblingElement(const char* name) 查找当前元素的兄弟元素(下一个兄弟元素)中的第一个具有指定名称的元素。(用于在当前元素的同级元素中查找指定名称的元素,而不是在子元素中查找。)
    // LastChildElement(const char* name) 查找当前元素的子元素中的最后一个具有指定名称的元素。(与 FirstChildElement 类似,但它返回匹配名称的最后一个子元素。)
    XMLElement* root = doc.FirstChildElement("root");  
    if (!root) {
        std::cout << "Root element 'root' not found in the XML document." << std::endl;
        return -1;
    }

    // 遍历 "person" 元素
    // root->FirstChildElement("person") 是 TinyXML2 提供的函数调用,它的作用是在当前元素(root)的子元素中查找名为 "person" 的第一个元素。
    // 如果找到,返回该元素的指针;如果没有找到,返回空指针。当返回personElement为空时,循环结束。这是for的典型用法。
    for (XMLElement* personElement = root->FirstChildElement("person"); personElement; personElement = personElement->NextSiblingElement("person")) {
        const char* name = personElement->Attribute("name");  // Attribute("name") 获取名为 "name" 的属性的值。如果属性不存在,它会返回空指针(nullptr)。
        const char* text = personElement->GetText();  // GetText()获取当前元素的文本内容。如果没有文本内容,它会返回空指针。

        if (name) {
            std::cout << "Name: " << name << std::endl;
        }

        if (text) {
            std::cout << "Text: " << text << std::endl;
        }
        
        personElement->SetAttribute("name","xiaoming"); // 修改
        personElement->SetText("100010111010100");
    }
    doc.SaveFile("examples.xml");  // 保存文件

    return 0;
}

3)读取未知xml文件

#include "tinyxml2.h"
#include <iostream>

using namespace tinyxml2;

int main() {
    // 创建XML文档
    XMLDocument doc;

    // 加载XML文件
    XMLError loadResult = doc.LoadFile("D:\\Temp\\WorkSpace\\C++\\example.xml");

    // 检查加载操作是否成功
    if (loadResult != XML_SUCCESS) {
        return -1;
    }

    // RootElement(): 这是用于获取XML文档的根元素的方法。它返回XMLDocument的根元素,通常是XML文件的最顶层元素。
    XMLElement* root = doc.RootElement();

    if (root) {
        // 遍历整个 XML 结构
        // NextSiblingElement() 函数用于获取同一层级的下一个元素
        // FirstChildElement(): 该方法用于获取当前元素的第一个子元素,而不需要指定名称。
        for (XMLElement* element = root->FirstChildElement(); element; element = element->NextSiblingElement()) {
            // 获取元素名称
            const char* elementName = element->Name();
            std::cout << "Element Name: " << elementName << std::endl;

            // 遍历元素的属性
            for (const XMLAttribute* attr = element->FirstAttribute(); attr; attr = attr->Next()) {
                const char* attrName = attr->Name();
                const char* attrValue = attr->Value();
                std::cout << "Attribute: " << attrName << " = " << attrValue << std::endl;
            }

            // 获取元素的文本内容
            const char* text = element->GetText();
            if (text) {
                std::cout << "Text: " << text << std::endl;
            }

            std::cout << std::endl;
        }
    } else {
        std::cout << "Root element not found in the XML document." << std::endl;
    }

    return 0;
}

注:
RootElement(): 用于获取XML文档的根元素,可以不指定元素名称。
NextSiblingElement(): 用于获取当前元素的下一个兄弟元素,可以不指定名称,只是返回同一层级下的下一个兄弟元素。
PreviousSiblingElement(): 用于获取同一层级的前一个兄弟元素,可以不指定名称
FirstChildElement(): 用于获取当前元素的第一个子元素,可以不指定名称。
LastChildElement(): 用于获取当前元素的最后一个子元素,可以不指定名称。

Parent(): 用于获取当前元素的父元素。
DeleteChild(): 用于删除一个子元素。
GetText(): 用于获取元素的文本内容。
SetText(): 用于设置元素的文本内容。
Name(): 用于获取元素的名称(标签名)。
Attribute(): 用于获取元素的属性值。
FirstAttribute(): 用于获取第一个属性。
NextAttribute(): 用于获取下一个属性。

eg:对于<property name="ShowQuestClearCount" value="1"/>来说
	Name 是property
	Attribute 是name和value
	Value 是ShowQuestClearCount和1

InsertEndChild(): 用于将一个节点插入为父元素的最后一个子节点。
InsertFirstChild(): 用于将一个节点插入为父元素的第一个子节点。