加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

如何使用 TinyXML 在内存中操作 xml 格式的内容

发布时间:2020-12-16 09:01:24 所属栏目:百科 来源:网络整理
导读:http://www.cnblogs.com/cy568searchx/archive/2013/02/26/2933815.html 如何使用 TinyXML 在内存中操作 xml 格式的内容 例子 xml 内容: ?xml version="1.0" encoding="UTF-8" ? Config Database ip="192.168.1.33" port="3306" / List Channel count="5"电

http://www.cnblogs.com/cy568searchx/archive/2013/02/26/2933815.html


如何使用 TinyXML 在内存中操作 xml 格式的内容

例子 xml 内容:
<?xml version="1.0" encoding="UTF-8" ?>
<Config>
<Database ip="192.168.1.33" port="3306" />
<List>
<Channel count="5">电视剧</Channel>
<Channel count="5">电影</Channel>
</List>
</Config>


1. 分析一段保存在内存中的 xml 内容 (代码见下方)

1) xml 内容中如果有中文,必须转成 UTF-8格式,否则可能会出问题,比如此例中,"电视剧"的中文 gb2312 编码会影响到后面的 "</Channel>",导致取这个节点的 text 时,得到的结果是: "电视剧</Channel>",而取下一个节点时将找不到节点。

2)使用 TiXmlDocument 与 TiXmlHandle 的区别: 一次取多级子节点元素时,当某一级节点不存在,用 doc (TiXmlDocument) 会出现异常,程序崩溃,而用 docHandle (TiXmlHandle) 则不会有异常。
比如:
databaseElement = doc.FirstChildElement( "Conf" )->FirstChildElement( "Database" ); // 异常,崩溃
databaseElement = docHandle.FirstChild( "Conf" ).FirstChild( "Database" ).ToElement(); // 不会异常,databaseElement 为 0
databaseElement = docHandle.FirstChildElement( "Conf" ).FirstChildElement( "Database" ).ToElement(); // 不会异常,databaseElement 为 0
后两种写法的效果是一样的。

以下为示例代码,buffer 中保存着上面例子的 xml 内容:

  1. voidCxmlDlg::ParseXML()
  2. {
  3. char*buffer="<?xmlversion="1.0"encoding="UTF-8"?>
  4. <Config>
  5. <Databaseip="192.168.1.33"port="3306"/>
  6. <List>
  7. <Channelcount="5">电视剧</Channel>
  8. <Channelcount="5">电影</Channel>
  9. </List>
  10. </Config>";
  11. charutf8[256]={0};
  12. if(MBSToUTF8(utf8,sizeof(utf8),buffer)<=0)//此函数见我之前关于TinyXML的文章
  13. return;
  14. TiXmlDocumentdoc;
  15. doc.Parse(utf8);
  16. TiXmlElement*databaseElement=0;
  17. TiXmlElement*listElement=0;
  18. TiXmlElement*channelElement=0;
  19. TiXmlHandledocHandle(&doc);
  20. databaseElement=docHandle.FirstChild("Config").FirstChild("Database").ToElement();
  21. assert(databaseElement);
  22. //取得字符串属性的内容
  23. constchar*ip=databaseElement->Attribute("ip");
  24. //取得整型属性的值
  25. intport=0;
  26. databaseElement->QueryIntAttribute("port",&port);
  27. intcount=0;
  28. charcontent[32]={0};
  29. listElement=docHandle.FirstChild("Config").FirstChild("List").ToElement();
  30. assert(listElement);
  31. for(channelElement=listElement->FirstChildElement("Channel");channelElement;channelElement=channelElement->NextSiblingElement("Channel"))
  32. {
  33. channelElement->QueryIntAttribute("count",&count);
  34. UTF8ToMBS(content,sizeof(content),channelElement->GetText());
  35. }
  36. }


2. 合成一段 xml 内容保存在内存中 (代码见下方)

有两种写法:
1) 第一种使用栈空间,声明为局部变量,链接 TiXmlElement 的局部对象时必须用 Insert 系列的函数: InsertEndChild / InsertAfterChild / InsertBeforeChild,如果使用 LinkEndChild,在对象释放时会有异常。原因正如 hoyt00 所说:"因为 Insert 系列的函数插入的是结点的副本(包括所有子结点),而 LinkEndChild 插入的就是你创建的对象。"

2) 第二种使用堆空间,动态分配对象,链接 TiXmlElement 时必须用 LinkEndChild 函数,这样在最后 delete TiXmlDocument 对象时,TinyXML 内部才会帮你把动态生成的对象释放掉。

// 参考了 hoyt00 的文章:http://blog.csdn.net/hoyt00/article/details/6769883:
(1)TiXmlDocument对象最好在栈上创建,如果在堆上创建了,那你必须得自己销毁它,千万不要像别的对象一样new出了就不管了.
(2)除了TiXmlDocument对象,树中的别的结点对象,必须是堆上创建的,千万不要把栈上对象的地址链接(LinkEndChild)到树中,因为栈上对象是不能用delete销毁的,当然TinyXml也有对栈上对象插入的方法,以下会说到.
(3)除了文档结点,new出的所有结点对象必须被链接到一个父亲结点上,才可以不用管对象的delete,而且必须不能管,不然有可能整棵树会被破坏而得不到正确的遍历和析构,如果new出的对象从来没链接到某棵树上,而且将来也不打算链接,无论有没有别的结点链接到它身上,你都必须手动delete它.
(4)不要尝试链接已经被别的结点链接过的指针,很显然,这会造成无法估量的麻烦,不用多说,大家都懂的.

写法一:

voidCxmlDlg::MakeXML1()
  • //生成XML内容
  • TiXmlDocumentdoc;
  • TiXmlElementconfig("Config");
  • TiXmlElementdatabase("Database");
  • database.SetAttribute("ip","192.168.1.33");
  • database.SetAttribute("port",3306);
  • config.InsertEndChild(database);
  • TiXmlElementlist("List");
  • charutf8[32]={0};
  • TiXmlElementchannel1("Channel");
  • channel1.SetAttribute("count",5);
  • MBSToUTF8(utf8,"电视剧");
  • TiXmlTexttext1(utf8);
  • channel1.InsertEndChild(text1);
  • list.InsertEndChild(channel1);
  • TiXmlElementchannel2("Channel");
  • channel2.SetAttribute("count","电影");
  • TiXmlTexttext2(utf8);
  • channel2.InsertEndChild(text2);
  • list.InsertEndChild(channel2);
  • config.InsertEndChild(list);
  • doc.InsertEndChild(config);
  • TiXmlPrinterprinter;
  • printer.SetIndent(0);//设置缩进字符,设为0表示不使用缩进。默认为4个空格,也可设为't'
  • doc.Accept(&printer);
  • charcontent[256]={0};
  • intsize=printer.Size();
  • assert(size<sizeof(content));
  • strcpy_s(content,printer.CStr());

  • 写法二:

    voidCxmlDlg::MakeXML2()
  • TiXmlDocument*doc=newTiXmlDocument();
  • TiXmlElement*config=newTiXmlElement("Config");
  • TiXmlElement*database=newTiXmlElement("Database");
  • database->SetAttribute("ip",0); background-color:inherit">database->SetAttribute("port",0); background-color:inherit">config->LinkEndChild(database);
  • TiXmlElement*list=newTiXmlElement("List");
  • TiXmlElement*channel1=newTiXmlElement("Channel");
  • channel1->SetAttribute("count",0); background-color:inherit">TiXmlText*text1=newTiXmlText(utf8);
  • channel1->LinkEndChild(text1);
  • list->LinkEndChild(channel1);
  • TiXmlElement*channel2=channel2->SetAttribute("count",0); background-color:inherit">TiXmlText*text2=channel2->LinkEndChild(text2);
  • list->LinkEndChild(channel2);
  • config->LinkEndChild(list);
  • doc->LinkEndChild(config);
  • printer.SetIndent(0);
  • doc->Accept(&printer);
  • charcontent[512]={0};
  • memcpy(content,printer.CStr(),printer.Size());
  • deletedoc;
  • 3.TinyXml 保存时如何处理缩进和行结尾

    1) 处理缩进:
    a.如果是保存文件,TinyXML 默认用4个空格做为缩进,根据节点的深度不同,缩进为4个空格的倍数,如果想去掉缩进,需要查找 TinyXML 源文件中所有写4个空格的地方(一共是5处),注释掉或换成你想要的缩进字符,也可以对 TinyXML 做一个改进,增加一个函数用于设置缩进字符,可以设为NULL,即无缩进。
    b.如果是保存到内存中,在 TiXmlPrinter 中有一个函数:SetIndent(),可以设置缩进字符,也可以设为 NULL。

    2) 处理行结尾: a.如果是保存文件,TinyXML 会在每行的结尾用fprintf()写一个 'n',在 Windows 上,fprintf 写入文件的 'n' 都会被转换为 "rn"。 b.如果是保存到内存中,在 TiXmlPrinter 中有一个函数:SetLineBreak(),可以设置行结尾字符,也可以设为 NULL。

    (编辑:李大同)

    【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    • 推荐文章
        热点阅读