TinyXML2
- 原始字符串字面量
- TinyXML2
- 1. XML文档操作
- 1.1 LoadFile(const char* filename)
- 1.2SaveFile(const char* filename)
- 1.3RootElement()
- 1.4Parse(const char* xml)
- 2.元素操作
- 2.1 FirstChildElement(const char* name = nullptr)
- 2.2 NextSiblingElement(const char* name = nullptr)
- 2.3 SetName(const char* name)
- 2.4 DeleteChild(XMLElement* child)
- 3. 属性操作
- 3.1SetAttribute(const char* name, const char* value)
- 3.2 Attribute(const char* name)
- 3.3 DeleteAttribute(const char* name)
- 4. 文本操作
- 4.1 SetText(const char* text)
- 4.2 GetText()
- 5. 新建元素和节点
- 5.1 NewElement(const char* name)
- 5.2 InsertFirstChild(XMLNode* child)
- 5.3 InsertEndChild(XMLNode* child)
- 6. 错误处理
- 6.1 ErrorID()
- 6.2ErrorStr()
- 附录:XML文件格式
- 命名空间
- 模式位置
- 简单的XML文件
- 复杂的XML文件
原始字符串字面量
- 原始字符串字面量是 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
- TinyXML2 是一个轻量级的 XML 解析库,专为简单和快速设计,适合嵌入式系统、小型应用或需要解析/生成 XML 的程序。TinyXML2 的核心功能包括 XML 的读取、修改和写入。
- 跨平台:纯 C++ 编写,可在 Windows、Linux、macOS 等平台上使用。
- 无需外部依赖:仅需单个头文件和源文件(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文件格式
-
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>
- 声明部分
-
XML规则
- 标签匹配
标签匹配:每个开始标签必须有对应的结束标签<name>张三</name>
单标签形式需要使用斜杠
- 区分大小写
XML区分大小写,例如和是不同的标签。
- 属性值必须使用引号:可以是单引号或双引号<person gender="male"></person>
-
转义字符
特殊字符 | 转义符 | 示例代码 | 输出效果 |
---|---|---|---|
& | & | <text>AT&T</text> | <text>AT&T</text> |
< | < | <text>1 < 2</text> | <text>1 < 2</text> |
> | > | <text>3 > 2</text> | <text>3 > 2</text> |
' | ' | <attribute value='John's book' /> | <attribute value='John's book' /> |
" | " | <attribute value="He said "Hello"" /> | <attribute value="He said "Hello"" /> |
命名空间
- 由来
- XML 中,标签名是自由定义的,不同的 XML 文档中可能会出现相同名称的标签。如果多个 XML 文件需要合并或扩展,很容易发生命名冲突。命名空间为标签和属性分配一个唯一的标识符,解决了冲突问题。
- 命名空间实际上是一个唯一的 URI(Uniform Resource Identifier),通常是一个 URL(但不需要真实存在)。它标识某一组标签属于特定的上下文。
- 语法
- 默认命名空间
<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>