TinyXML2的一些用法

发布于:2024-12-06 ⋅ 阅读:(36) ⋅ 点赞:(0)

原始字符串字面量

  • 原始字符串字面量是 C++ 提供的一种字符串表示法,用来简化特殊字符的处理(例如换行符、反斜杠)和避免过多的转义字符。它的引入是为了让字符串更可读、更易于书写,尤其是涉及正则表达式、文件路径等场景。
  • 语法
原始字符串字面量以 R"delimiter(raw_characters)delimiter" 的形式表示:

delimiter 是用户定义的分隔符,可以用任意字符,但不能包含空白字符或括号。
raw_characters 是原始字符串的内容,所有字符将被保留原样。

  • 特点
    • 支持多行字符串:原始字符串字面量可以直接包含换行符,而无需使用 \n。
    • 无需转义字符:在常规字符串中,特殊字符(如换行符 \n 或双引号 ")需要用反斜杠 \ 转义。
    • 灵活的分隔符:如果字符串中包含了 “)”,可以使用自定义分隔符避免冲突。
    std::string raw_str = R"delimiter(This is a raw string with ")".)delimiter";
    
    
    • 可嵌套引号:原始字符串字面量允许在字符串中直接包含双引号。
  • 使用方法同普通字符串一样。

TinyXML2

  1. TinyXML2 是一个轻量级的 XML 解析库,专为简单和快速设计,适合嵌入式系统、小型应用或需要解析/生成 XML 的程序。TinyXML2 的核心功能包括 XML 的读取、修改和写入。
  2. 跨平台:纯 C++ 编写,可在 Windows、Linux、macOS 等平台上使用。
  3. 无需外部依赖:仅需单个头文件和源文件(tinyxml2.h 和 tinyxml2.cpp)。

1. XML文档操作

1.1 LoadFile(const char* filename)

功能:将 XML 文档保存到文件。
参数:filename 是文件路径。
返回值:保存成功返回 XML_SUCCESS,否则返回错误码。

XMLDocument doc;//表示整个 XML 文件,负责加载、解析、保存。
if (doc.LoadFile("example.xml") != XML_SUCCESS) {
    std::cerr << "Failed to load XML file!" << std::endl;
}
1.2SaveFile(const char* filename)

功能:将 XML 文档保存到文件。
参数:filename 是文件路径。
返回值:保存成功返回 XML_SUCCESS,否则返回错误码。

if (doc.SaveFile("output.xml") != XML_SUCCESS) {
    std::cerr << "Failed to save XML file!" << std::endl;
}
1.3RootElement()

功能:获取 XML 文档的根元素。
返回值:指向根元素的指针,如果没有根元素返回 nullptr。

XMLElement* root = doc.RootElement();
if (!root) {
    std::cerr << "No root element found!" << std::endl;
} else {
    std::cout << "Root element: " << root->Name() << std::endl;
}

1.4Parse(const char* xml)

功能:直接解析 XML 字符串。
参数:xml 是一个 XML 格式的字符串。
返回值:解析成功返回 XML_SUCCESS,否则返回错误码。

const char* xml = "<Root><Child>Text</Child></Root>";
if (doc.Parse(xml) != XML_SUCCESS) {
    std::cerr << "Failed to parse XML string!" << std::endl;
}
示例
	// 1. 基本解析
XMLDocument doc;
// 解析简单的XML字符串
const char* xml = "<Root><Child>Hello</Child></Root>";
if (doc.Parse(xml) == XML_SUCCESS) {
    XMLElement* root = doc.FirstChildElement("Root");
    XMLElement* child = root->FirstChildElement("Child");
    const char* text = child->GetText();  // 获取 "Hello"
}

// 2. 解析带属性的XML
const char* xmlWithAttr = R"(
    <Person id="1" name="John">
        <Age>30</Age>
        <Address city="New York">
            <Street>Broadway</Street>
        </Address>
    </Person>
)";
if (doc.Parse(xmlWithAttr) == XML_SUCCESS) {
    XMLElement* person = doc.FirstChildElement("Person");
    const char* name = person->Attribute("name");  // 获取 "John"
    
    XMLElement* address = person->FirstChildElement("Address");
    const char* city = address->Attribute("city");  // 获取 "New York"
}

// 3. 解析列表数据
const char* xmlList = R"(
    <Inventory>
        <Item id="1" name="Apple" price="0.5"/>
        <Item id="2" name="Banana" price="0.3"/>
        <Item id="3" name="Orange" price="0.4"/>
    </Inventory>
)";
class InventoryParser {
public:
    struct Item {
        int id;
        string name;
        double price;
    };

    static vector<Item> parseItems(const char* xml) {
        vector<Item> items;
        XMLDocument doc;
        
        if (doc.Parse(xml) == XML_SUCCESS) {
            XMLElement* inventory = doc.FirstChildElement("Inventory");
            for (XMLElement* elem = inventory->FirstChildElement("Item");
                 elem != nullptr;
                 elem = elem->NextSiblingElement("Item")) {
                
                Item item;
                item.id = elem->IntAttribute("id");
                item.name = elem->Attribute("name");
                item.price = elem->DoubleAttribute("price");
                items.push_back(item);
            }
        }
        return items;
    }
};

// 4. 解析嵌套结构
const char* xmlNested = R"(
    <Company>
        <Department name="Engineering">
            <Employee id="1">
                <Name>John Doe</Name>
                <Position>Developer</Position>
                <Skills>
                    <Skill>C++</Skill>
                    <Skill>Python</Skill>
                </Skills>
            </Employee>
        </Department>
    </Company>
)";
class CompanyParser {
public:
    static void parseEmployee(XMLElement* empElement) {
        string name = empElement->FirstChildElement("Name")->GetText();
        string position = empElement->FirstChildElement("Position")->GetText();
        
        vector<string> skills;
        XMLElement* skillsElem = empElement->FirstChildElement("Skills");
        for (XMLElement* skill = skillsElem->FirstChildElement("Skill");
             skill != nullptr;
             skill = skill->NextSiblingElement("Skill")) {
            skills.push_back(skill->GetText());
        }
    }
};

// 5. 错误处理
class XMLParser {
public:
    static bool parseWithErrorHandling(const char* xml) {
        XMLDocument doc;
        XMLError err = doc.Parse(xml);
        
        switch (err) {
            case XML_SUCCESS:
                return true;
            case XML_ERROR_FILE_NOT_FOUND:
                cerr << "XML file not found!" << endl;
                break;
            case XML_ERROR_PARSING_ELEMENT:
                cerr << "Error parsing element!" << endl;
                break;
            case XML_ERROR_PARSING_ATTRIBUTE:
                cerr << "Error parsing attribute!" << endl;
                break;
            default:
                cerr << "Unknown XML error!" << endl;
        }
        return false;
    }
};

// 6. 配置文件解析
const char* configXml = R"(
    <Config>
        <Database>
            <Host>localhost</Host>
            <Port>3306</Port>
            <Username>root</Username>
            <Password>secret123</Password>
        </Database>
        <Server>
            <Port>8080</Port>
            <MaxConnections>100</MaxConnections>
        </Server>
    </Config>
)";
class ConfigParser {
public:
    struct DBConfig {
        string host;
        int port;
        string username;
        string password;
    };

    struct ServerConfig {
        int port;
        int maxConnections;
    };

    static pair<DBConfig, ServerConfig> parseConfig(const char* xml) {
        XMLDocument doc;
        DBConfig db;
        ServerConfig server;
        
        if (doc.Parse(xml) == XML_SUCCESS) {
            XMLElement* config = doc.FirstChildElement("Config");
            
            // 解析数据库配置
            XMLElement* dbElem = config->FirstChildElement("Database");
            db.host = dbElem->FirstChildElement("Host")->GetText();
            db.port = atoi(dbElem->FirstChildElement("Port")->GetText());
            db.username = dbElem->FirstChildElement("Username")->GetText();
            db.password = dbElem->FirstChildElement("Password")->GetText();
            
            // 解析服务器配置
            XMLElement* serverElem = config->FirstChildElement("Server");
            server.port = atoi(serverElem->FirstChildElement("Port")->GetText());
            server.maxConnections = atoi(serverElem->FirstChildElement("MaxConnections")->GetText());
        }
        
        return {db, server};
    }
};

2.元素操作

2.1 FirstChildElement(const char* name = nullptr)

功能:获取元素的第一个子元素。如果 name 参数不为空,则返回名称匹配的第一个子元素。
参数:name 是可选参数,表示子元素的名称。
返回值:指向第一个子元素的指针,如果没有找到返回 nullptr。

XMLElement* firstChild = root->FirstChildElement();
if (firstChild) {
    std::cout << "First child element: " << firstChild->Name() << std::endl;
}

2.2 NextSiblingElement(const char* name = nullptr)

功能:获取当前元素的下一个同级元素。如果 name 参数不为空,则返回名称匹配的下一个同级元素。
参数:name 是可选参数,表示同级元素的名称。
返回值:指向下一个同级元素的指针,如果没有找到返回 nullptr。

for (XMLElement* child = root->FirstChildElement(); child != nullptr; child = child->NextSiblingElement()) {
    std::cout << "Sibling element: " << child->Name() << std::endl;
}

2.3 SetName(const char* name)

功能:设置元素的名称。
参数:name 是新名称的字符串。

element->SetName("NewName");

2.4 DeleteChild(XMLElement* child)

功能:删除当前元素的指定子元素。
参数:child 是需要删除的子元素指针。

root->DeleteChild(child);

3. 属性操作

3.1SetAttribute(const char* name, const char* value)

功能:设置元素的字符串属性。
参数:name 是属性名,value 是属性值。

element->SetAttribute("key", "value");
3.2 Attribute(const char* name)

功能:获取元素指定名称的属性值。
参数:name 是属性名。
返回值:指向属性值的字符串指针,如果属性不存在返回 nullptr。

const char* attrValue = element->Attribute("key");
if (attrValue) {
    std::cout << "Attribute value: " << attrValue << std::endl;
}

3.3 DeleteAttribute(const char* name)

功能:删除元素指定名称的属性。
参数:name 是属性名。

element->DeleteAttribute("key");

4. 文本操作

4.1 SetText(const char* text)

功能:设置元素的文本内容。
参数:text 是字符串,表示要设置的文本内容。

element->SetText("This is text content");

4.2 GetText()

功能:获取元素的文本内容。
返回值:指向文本内容的字符串指针,如果没有文本内容返回 nullptr。

const char* text = element->GetText();
if (text) {
    std::cout << "Text content: " << text << std::endl;
}

5. 新建元素和节点

5.1 NewElement(const char* name)

功能:创建一个新的元素。
参数:name 是新元素的名称。
返回值:指向新创建的元素的指针。

XMLElement* newElement = doc.NewElement("NewElement");

5.2 InsertFirstChild(XMLNode* child)

功能:将一个子元素插入到当前元素的最前面。
参数:child 是要插入的子元素指针。

root->InsertFirstChild(newElement);

5.3 InsertEndChild(XMLNode* child)

功能:将一个子元素插入到当前元素的末尾。
参数:child 是要插入的子元素指针。

root->InsertEndChild(newElement);

6. 错误处理

6.1 ErrorID()

功能:返回文档的错误代码。

if (doc.ErrorID() != XML_SUCCESS) {
    std::cerr << "Error occurred: " << doc.ErrorID() << std::endl;
}
6.2ErrorStr()

功能:返回错误信息字符串。

if (doc.ErrorID() != XML_SUCCESS) {
    std::cerr << "Error details: " << doc.ErrorStr() << std::endl;
}

附录:XML文件格式

  1. XML的基本结构

    • 声明部分
      XML文件的开头是声明,表示XML的版本和编码格式
    <?xml version="1.0" encoding="UTF-8"?>
    
    
    • 根元素
      XML文件必须有且只有一个根元素,所有其他内容都嵌套在根元素中
    <root>
        <!-- 子元素 -->
    </root>
    
    
    • 元素
      元素是XML的基本组成单位,通常由开始标签和结束标签组成
    <element>内容</element>
    
     - 可以嵌套子元素。
     - 可以携带属性
    
    <element attribute="value">内容</element>
    
    
     - 属性
    

    属性是描述元素的附加信息,格式为key=“value”

    <book id="1" author="Author Name">Book Title</book>
    
    
     - 注释
    

    注释用于添加说明性文字

    <!-- 这是一个注释 -->
    
     - 文本内容
    
    <name>张三</name>
    
    
  2. XML规则
    - 标签匹配
    标签匹配:每个开始标签必须有对应的结束标签

    <name>张三</name>
    
    

    单标签形式需要使用斜杠
    - 区分大小写
    XML区分大小写,例如和是不同的标签。
    - 属性值必须使用引号:可以是单引号或双引号

    <person gender="male"></person>
    
    
  3. 转义字符

特殊字符 转义符 示例代码 输出效果
& &amp; <text>AT&amp;T</text> <text>AT&T</text>
< &lt; <text>1 &lt; 2</text> <text>1 < 2</text>
> &gt; <text>3 &gt; 2</text> <text>3 > 2</text>
' &apos; <attribute value='John&apos;s book' /> <attribute value='John's book' />
" &quot; <attribute value="He said &quot;Hello&quot;" /> <attribute value="He said "Hello"" />

命名空间

  1. 由来
  • XML 中,标签名是自由定义的,不同的 XML 文档中可能会出现相同名称的标签。如果多个 XML 文件需要合并或扩展,很容易发生命名冲突。命名空间为标签和属性分配一个唯一的标识符,解决了冲突问题。
  • 命名空间实际上是一个唯一的 URI(Uniform Resource Identifier),通常是一个 URL(但不需要真实存在)。它标识某一组标签属于特定的上下文。
  1. 语法
  • 默认命名空间
<root xmlns="http://example.com/namespace">
    <child>Content</child>
</root>
<!--作用范围:没有前缀的所有标签(<root><child>)都属于这个命名空间。-->
  • 带前缀的命名空间
<root xmlns:ns="http://example.com/namespace">
    <ns:child>Content</ns:child>
</root>
<!--xmlns:ns="http://example.com/namespace" 声明了带前缀的命名空间-->
<!--标签 <ns:child> 使用了 ns 前缀,表示它属于命名空间 http://example.com/namespace-->
<!--作用范围:只有使用了 ns: 前缀的标签。-->

  • 解决的问题
<person xmlns:p="http://example.com/person">
    <p:name>John</p:name>
</person>

<product xmlns:prod="http://example.com/product">
    <prod:name>Smartphone</prod:name>
</product>

模式位置

简单的XML文件

<?xml version="1.0" encoding="UTF-8"?>
<!-- 这是一个简单的 XML 文件,描述书店中的书籍信息 -->
<bookstore>
    <book id="1">
        <title>XML Basics</title>
        <author>John Doe</author>
        <price currency="USD">29.99</price>
    </book>
    <book id="2">
        <title>Learning XML</title>
        <author>Jane Smith</author>
        <price currency="EUR">39.99</price>
    </book>
</bookstore>

复杂的XML文件

<?xml version="1.0" encoding="UTF-8"?>
<!-- 复杂 XML 文件,描述一个电子商务平台的订单信息 -->
<ecommerce xmlns="http://example.com/ecommerce" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://example.com/ecommerce ecommerce.xsd">
    <order id="1001" status="shipped">
        <customer>
            <name>John Doe</name>
            <email>john.doe@example.com</email>
            <phone>+123456789</phone>
            <address>
                <street>123 Main St</street>
                <city>Springfield</city>
                <state>IL</state>
                <zipcode>62704</zipcode>
                <country>USA</country>
            </address>
        </customer>
        <items>
            <item id="p101">
                <name>Smartphone</name>
                <quantity>1</quantity>
                <price currency="USD">699.99</price>
            </item>
            <item id="p102">
                <name>Wireless Headphones</name>
                <quantity>2</quantity>
                <price currency="USD">59.99</price>
            </item>
        </items>
        <payment>
            <method>Credit Card</method>
            <transaction_id>TX123456789</transaction_id>
            <amount currency="USD">819.97</amount>
        </payment>
        <shipping>
            <method>Express</method>
            <tracking_number>EXP123456789</tracking_number>
            <date>2024-11-25</date>
        </shipping>
    </order>
</ecommerce>


网站公告

今日签到

点亮在社区的每一天
去签到