当前位置: 首页 > 我的程序代码 > 正文

初步接触TinyXML2

写这篇文章纯属偶然。
我很少接触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>
</Root>

下面再给出解析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日午后

本文固定链接: http://www.latelee.org/my-library/first-time-to-tinyxml2.html

如无特别说明,迟思堂工作室文章均为原创,转载请注明: 初步接触TinyXML2 | 迟思堂工作室

目前暂无评论

发表评论

*

快捷键:Ctrl+Enter