写这篇文章纯属偶然。
我很少接触xml,工作上也没使用过。即使使用,也是别人做好的接口,直接调用。最近的一个项目中,因为某些策略问题,造成项目的代码十分混乱,东拼西凑,做成了个不像样的东西。其中有部分是设备端与PC端的网络协议传输,使用到了自定义的xml协议,因为某些原因,这个协议不断地改进但未同步更新,幸亏做了兼容,但部分新加协议未在设备端更新,所以要添加进去,不过某同事忙于其它事务,所以只有我上了(个中故事等有空写篇文章出来)。
闲话少说,为了研究一下xml,自己抽空练习使用了一下tinyxml,为了避免与公司发生不必要的纠纷,特别使用了tinyxml第二版本(公司代码使用第一版本),特地在周末写程序。
tinyxml的第二版本改动很多,参考官方网站说明。
在使用前要包含头文件并要使用tinyxml2命令空间。如下:
#include "tinyxml2.h" using namespace tinyxml2;
下面给出创建xml的示例函数:
// 创建xml示例 int createXML(const char* xmlFile) { XMLDocument* doc = new XMLDocument(); if (doc == NULL) { return -1; } // dec XMLDeclaration *dec = NULL; dec = doc->NewDeclaration("xml version=\"1.0\" encoding=\"gb2312\" standalone=\"yes\""); //dec = doc->NewDeclaration(); // 默认为utf-8 if (dec == NULL) { return -1; } doc->LinkEndChild(dec); //////////////////////////////// // 根元素 XMLElement* root = doc->NewElement("Root"); if (root == NULL) { return -1; } root->SetAttribute("ver", "1.0"); doc->LinkEndChild(root); //////////////////////////////// // 第一级子节点 XMLElement* fstEle = doc->NewElement("subClass1"); XMLText* fstText = doc->NewText("Text1"); fstEle->SetAttribute("attribute1", "foo"); fstEle->SetAttribute("attribute2", "bar"); fstEle->LinkEndChild(fstText); root->LinkEndChild(fstEle); // 第二个同级节点 XMLElement* fstEle1 = doc->NewElement("subClass2"); XMLText* fstText1 = doc->NewText("Text2"); fstEle1->SetAttribute("attribute1", "foo"); fstEle1->SetAttribute("attribute2", "bar"); fstEle1->LinkEndChild(fstText1); root->LinkEndChild(fstEle1); // 第三个同级节点,但没有Text,可以再设一级子节点 XMLElement* thdEle = doc->NewElement("subClass3"); thdEle->SetAttribute("attribute1", "foo"); root->LinkEndChild(thdEle); // 第三个节点的子节点 XMLElement* sndEle = doc->NewElement("sub_subClass1"); XMLText* sndText = doc->NewText("subText"); sndEle->SetAttribute("attribute", "foobar"); sndEle->LinkEndChild(sndText); thdEle->LinkEndChild(sndEle); // 第四个节点 XMLElement* fstEle2 = doc->NewElement("subClass4"); XMLText* fstText2 = doc->NewText("Text4"); fstEle2->SetAttribute("attribute1", "foo"); fstEle2->SetAttribute("attribute2", "bar"); fstEle2->LinkEndChild(fstText2); root->LinkEndChild(fstEle2); /////////////////////////////////// // 保存,打印 doc->SaveFile(xmlFile); XMLPrinter printer; doc->Print(&printer); const char* xmlcstr = printer.CStr(); // 打印 printf("xml buffer: \n"); printf("%s\n", xmlcstr); /////////////////// #if 0 XMLElement* rootEle = NULL; XMLElement* node = NULL; rootEle = doc->RootElement(); if (rootEle == NULL) return -1; findNode(rootEle, "sub_subClass1", node); // text const char* text = NULL; findText(node, &text); printf("---- text: %s\n", text); const char* test_value = NULL; findAttribute(node, "apple", test_value); printf("xxxxx: %s\n", test_value); #endif delete doc; doc = NULL; return 0; }
结果如下:
<?xml version="1.0" encoding="gb2312" standalone="yes"?> <Root ver="1.0"> <subClass1 attribute1="foo" attribute2="bar">Text1</subClass1> <subClass2 attribute1="foo" attribute2="bar">Text2</subClass2> <subClass3 attribute1="foo"> <sub_subClass1 attribute="foobar">subText</sub_subClass1> </subClass3> <subClass4 attribute1="foo" attribute2="bar">Text4</subClass4>
下面再给出解析xml内容的示例函数:
int findElement(XMLElement* root) { if (root == NULL) return -1; XMLElement* ele = NULL; int i = 0; for (ele = root->FirstChildElement(); ele; ele = ele->NextSiblingElement()) { printf("Element: %s Text: %s\n", ele->Value(), ele->GetText()); const XMLAttribute* attr = NULL; for (attr = ele->FirstAttribute(), i = 0; attr; attr = attr->Next(), i++) { printf("attr(%d) (%s: %s)\n", i, attr->Name(), attr->Value()); } if (ele->FirstChildElement()) { printf("sub %s: \n", ele->Value()); findElement(ele); // 递归查找元素 } } return 0; } // 解析xml示例 int parseXML(const char* xmlFile) { XMLDocument* doc = new XMLDocument(); if (doc == NULL) { return -1; } doc->LoadFile(xmlFile); doc->Print(); // 声明 //todo // 根 XMLElement* root = doc->RootElement(); if (root == NULL) return -1; // 元素属性 const XMLAttribute* attr = NULL; for (attr = root->FirstAttribute(); attr; attr = attr->Next()) { printf("root: %s attr (%s: %s)\n", root->Value(), attr->Name(), attr->Value()); } // 查找元素并打印 findElement(root); return 0; }
结果如下:
root: Root attr (ver: 1.0) Element: subClass1 Text: Text1 attr(0) (attribute1: foo) attr(1) (attribute2: bar) Element: subClass2 Text: Text2 attr(0) (attribute1: foo) attr(1) (attribute2: bar) Element: subClass3 Text: (null) attr(0) (attribute1: foo) sub subClass3: Element: sub_subClass1 Text: subText attr(0) (attribute: foobar) Element: subClass4 Text: Text4 attr(0) (attribute1: foo) attr(1) (attribute2: bar)
tinyxml2的资料比较少,官方的示例及文档是比较权威的,可以参考一下。根据我的使用及查阅的资料,下面列举与第一版本改动的地方。
1、源文件个数减少至2个,即一个头文件(tinyxml2.h),一个实现文件(tinyxml2.cpp)。
2、加入了tinyxml2的命名空间。
3、对类名称作了修改,将TiXml**改为XML**,比如TiXmlElement改为XMLElement。
4、少了很多new,只有XMLDocument需要new,其它均由该类的方法进行封装。如下:
旧:
TiXmlDeclaration *dec= new TiXmlDeclaration("1.0","","");
新:
XMLDeclaration *dec = doc->NewDeclaration("xml version=\"1.0\" encoding=\"gb2312\" standalone=\"yes\"");
旧:
TiXmlElement *ele= new TiXmlElement("Root");
新:
XMLElement* root = doc->NewElement("Root");
5、网上有人讨论是否需要手动delete掉new出来的类,我没有在实际工作中使用到,所以不发表意见。在第二版中,示例代码只有XMLDocument才用delete,其它没有使用。所以上述代码也在最后delete。
资源:
tinyxml网站:http://www.grinninglizard.com/tinyxml2/
git仓库地址:https://github.com/leethomason/tinyxml2.git
迟,于2013年9月8日午后