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

 如何使用 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. void CxmlDlg::ParseXML()  
  2. {  
  3.     char * buffer = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\  
  4. <Config>\  
  5.     <Database ip=\"192.168.1.33\" port=\"3306\" />\  
  6.     <List>\  
  7.         <Channel count=\"5\">电视剧</Channel>\  
  8.         <Channel count=\"5\">电影</Channel>\  
  9.     </List>\  
  10. </Config>";  
  11.   
  12.     char utf8[256] = {0};  
  13.   
  14.     if( MBSToUTF8( utf8, sizeof(utf8), buffer ) <= 0 ) // 此函数见我之前关于 TinyXML 的文章  
  15.         return;  
  16.   
  17.     TiXmlDocument doc;  
  18.     doc.Parse(utf8);  
  19.   
  20.     TiXmlElement* databaseElement = 0;  
  21.     TiXmlElement* listElement = 0;  
  22.     TiXmlElement* channelElement = 0;  
  23.   
  24.     TiXmlHandle docHandle( &doc );  
  25.     databaseElement = docHandle.FirstChild( "Config" ).FirstChild( "Database" ).ToElement();  
  26.     assert( databaseElement  );  
  27.   
  28.     // 取得字符串属性的内容  
  29.     const char * ip = databaseElement->Attribute("ip");  
  30.   
  31.     // 取得整型属性的值  
  32.     int port = 0;  
  33.     databaseElement->QueryIntAttribute("port", &port );  
  34.   
  35.     int count = 0;  
  36.     char content[32] = {0};  
  37.   
  38.     listElement = docHandle.FirstChild( "Config" ).FirstChild( "List" ).ToElement();  
  39.     assert( listElement );  
  40.     for( channelElement = listElement->FirstChildElement("Channel"); channelElement; channelElement = channelElement->NextSiblingElement("Channel") )  
  41.     {  
  42.         channelElement->QueryIntAttribute("count", &count );  
  43.         UTF8ToMBS( content, sizeof(content), channelElement->GetText() );  
  44.     }  
  45. }  


 

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)不要尝试链接已经被别的结点链接过的指针, 很显然, 这会造成无法估量的麻烦, 不用多说, 大家都懂的.

 

写法一:

  1. void CxmlDlg::MakeXML1()  
  2. {  
  3.     // 生成 XML 内容  
  4.     TiXmlDocument doc;  
  5.   
  6.     TiXmlElement config("Config");  
  7.   
  8.     TiXmlElement database("Database");  
  9.     database.SetAttribute( "ip""192.168.1.33" );  
  10.     database.SetAttribute( "port", 3306 );  
  11.   
  12.     config.InsertEndChild( database );  
  13.   
  14.     TiXmlElement list("List");  
  15.   
  16.     char utf8[32] = {0};  
  17.   
  18.     TiXmlElement channel1("Channel");  
  19.     channel1.SetAttribute( "count", 5 );  
  20.   
  21.     MBSToUTF8( utf8, sizeof(utf8), "电视剧" );  
  22.     TiXmlText text1( utf8 );  
  23.     channel1.InsertEndChild( text1 );  
  24.     list.InsertEndChild( channel1 );  
  25.   
  26.     TiXmlElement channel2("Channel");  
  27.     channel2.SetAttribute( "count", 5 );  
  28.   
  29.     MBSToUTF8( utf8, sizeof(utf8), "电影" );  
  30.     TiXmlText text2( utf8 );  
  31.     channel2.InsertEndChild( text2 );  
  32.     list.InsertEndChild( channel2 );  
  33.   
  34.     config.InsertEndChild( list );  
  35.     doc.InsertEndChild( config );  
  36.   
  37.     TiXmlPrinter printer;  
  38.     printer.SetIndent( 0 ); // 设置缩进字符,设为 0 表示不使用缩进。默认为 4个空格,也可设为'\t'  
  39.     doc.Accept( &printer );  
  40.   
  41.     char content[256] = {0};  
  42.     int size = printer.Size();  
  43.     assert( size < sizeof(content) );  
  44.     strcpy_s( content, sizeof(content), printer.CStr() );  
  45. }  


 写法二:

  1. void CxmlDlg::MakeXML2()  
  2. {  
  3.     // 生成 XML 内容  
  4.     TiXmlDocument *doc = new TiXmlDocument();  
  5.   
  6.     TiXmlElement *config = new TiXmlElement("Config");  
  7.   
  8.     TiXmlElement *database = new TiXmlElement("Database");  
  9.     database->SetAttribute( "ip""192.168.1.33" );  
  10.     database->SetAttribute( "port", 3306 );  
  11.   
  12.     config->LinkEndChild( database );  
  13.   
  14.     TiXmlElement *list = new TiXmlElement("List");  
  15.   
  16.     char utf8[32] = {0};  
  17.   
  18.     TiXmlElement *channel1 = new TiXmlElement("Channel");  
  19.     channel1->SetAttribute( "count", 5 );  
  20.   
  21.     MBSToUTF8( utf8, sizeof(utf8), "电视剧" );  
  22.     TiXmlText *text1 = new TiXmlText( utf8 );  
  23.     channel1->LinkEndChild( text1 );  
  24.     list->LinkEndChild( channel1 );  
  25.   
  26.     TiXmlElement *channel2 = new TiXmlElement("Channel");  
  27.     channel2->SetAttribute( "count", 5 );  
  28.   
  29.     MBSToUTF8( utf8, sizeof(utf8), "电影" );  
  30.     TiXmlText *text2 = new TiXmlText( utf8 );  
  31.     channel2->LinkEndChild( text2 );  
  32.     list->LinkEndChild( channel2 );  
  33.   
  34.     config->LinkEndChild( list );  
  35.     doc->LinkEndChild( config );  
  36.   
  37.     TiXmlPrinter printer;  
  38.     printer.SetIndent( 0 );  
  39.     doc->Accept( &printer );  
  40.   
  41.     char content[512] = {0};  
  42.     int size = printer.Size();  
  43.     assert( size < sizeof(content) );  
  44.     memcpy( content, printer.CStr(), printer.Size() );  
  45.   
  46.     delete doc;  
  47. }  


 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值