如何 操作在内存中 xml 格式的内容
来源:互联网 发布:2017年10月cpi数据 编辑:程序博客网 时间:2024/06/11 10:04
如何使用 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 内容:
- void CxmlDlg::ParseXML()
- {
- char * buffer = "<?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>";
- char utf8[256] = {0};
- if( MBSToUTF8( utf8, sizeof(utf8), buffer ) <= 0 ) // 此函数见我之前关于 TinyXML 的文章
- return;
- TiXmlDocument doc;
- doc.Parse(utf8);
- TiXmlElement* databaseElement = 0;
- TiXmlElement* listElement = 0;
- TiXmlElement* channelElement = 0;
- TiXmlHandle docHandle( &doc );
- databaseElement = docHandle.FirstChild( "Config" ).FirstChild( "Database" ).ToElement();
- assert( databaseElement );
- // 取得字符串属性的内容
- const char * ip = databaseElement->Attribute("ip");
- // 取得整型属性的值
- int port = 0;
- databaseElement->QueryIntAttribute("port", &port );
- int count = 0;
- char content[32] = {0};
- listElement = docHandle.FirstChild( "Config" ).FirstChild( "List" ).ToElement();
- assert( listElement );
- for( channelElement = listElement->FirstChildElement("Channel"); channelElement; channelElement = channelElement->NextSiblingElement("Channel") )
- {
- channelElement->QueryIntAttribute("count", &count );
- UTF8ToMBS( content, sizeof(content), channelElement->GetText() );
- }
- }
2. 合成一段 xml 内容保存在内存中 (代码见下方)
有两种写法:
1) 第一种使用栈空间,声明为局部变量,链接 TiXmlElement 的局部对象时必须用 Insert 系列的函数: InsertEndChild / InsertAfterChild / InsertBeforeChild,如果使用 LinkEndChild,在对象释放时会有异常。原因正如 hoyt00 所说:"因为 Insert 系列的函数插入的是结点的副本(包括所有子结点),而 LinkEndChild 插入的就是你创建的对象。"
2) 第二种使用堆空间,动态分配对象,链接 TiXmlElement 时必须用 LinkEndChild 函数,这样在最后 delete TiXmlDocument 对象时,TinyXML 内部才会帮你把动态生成的对象释放掉。
(1)TiXmlDocument对象最好在栈上创建, 如果在堆上创建了, 那你必须得自己销毁它, 千万不要像别的对象一样new出了就不管了.
(2)除了TiXmlDocument对象, 树中的别的结点对象, 必须是堆上创建的, 千万不要把栈上对象的地址链接(LinkEndChild)到树中, 因为栈上对象是不能用delete销毁的, 当然TinyXml也有对栈上对象插入的方法, 以下会说到.
(3)除了文档结点, new出的所有结点对象必须被链接到一个父亲结点上, 才可以不用管对象的delete, 而且必须不能管, 不然有可能整棵树会被破坏而得不到正确的遍历和析构, 如果new出的对象从来没链接到某棵树上, 而且将来也不打算链接, 无论有没有别的结点链接到它身上, 你都必须手动delete它.
(4)不要尝试链接已经被别的结点链接过的指针, 很显然, 这会造成无法估量的麻烦, 不用多说, 大家都懂的.
写法一:
- void CxmlDlg::MakeXML1()
- {
- // 生成 XML 内容
- TiXmlDocument doc;
- TiXmlElement config("Config");
- TiXmlElement database("Database");
- database.SetAttribute( "ip", "192.168.1.33" );
- database.SetAttribute( "port", 3306 );
- config.InsertEndChild( database );
- TiXmlElement list("List");
- char utf8[32] = {0};
- TiXmlElement channel1("Channel");
- channel1.SetAttribute( "count", 5 );
- MBSToUTF8( utf8, sizeof(utf8), "电视剧" );
- TiXmlText text1( utf8 );
- channel1.InsertEndChild( text1 );
- list.InsertEndChild( channel1 );
- TiXmlElement channel2("Channel");
- channel2.SetAttribute( "count", 5 );
- MBSToUTF8( utf8, sizeof(utf8), "电影" );
- TiXmlText text2( utf8 );
- channel2.InsertEndChild( text2 );
- list.InsertEndChild( channel2 );
- config.InsertEndChild( list );
- doc.InsertEndChild( config );
- TiXmlPrinter printer;
- printer.SetIndent( 0 ); // 设置缩进字符,设为 0 表示不使用缩进。默认为 4个空格,也可设为'\t'
- doc.Accept( &printer );
- char content[256] = {0};
- int size = printer.Size();
- assert( size < sizeof(content) );
- strcpy_s( content, sizeof(content), printer.CStr() );
- }
写法二:
- void CxmlDlg::MakeXML2()
- {
- // 生成 XML 内容
- TiXmlDocument *doc = new TiXmlDocument();
- TiXmlElement *config = new TiXmlElement("Config");
- TiXmlElement *database = new TiXmlElement("Database");
- database->SetAttribute( "ip", "192.168.1.33" );
- database->SetAttribute( "port", 3306 );
- config->LinkEndChild( database );
- TiXmlElement *list = new TiXmlElement("List");
- char utf8[32] = {0};
- TiXmlElement *channel1 = new TiXmlElement("Channel");
- channel1->SetAttribute( "count", 5 );
- MBSToUTF8( utf8, sizeof(utf8), "电视剧" );
- TiXmlText *text1 = new TiXmlText( utf8 );
- channel1->LinkEndChild( text1 );
- list->LinkEndChild( channel1 );
- TiXmlElement *channel2 = new TiXmlElement("Channel");
- channel2->SetAttribute( "count", 5 );
- MBSToUTF8( utf8, sizeof(utf8), "电影" );
- TiXmlText *text2 = new TiXmlText( utf8 );
- channel2->LinkEndChild( text2 );
- list->LinkEndChild( channel2 );
- config->LinkEndChild( list );
- doc->LinkEndChild( config );
- TiXmlPrinter printer;
- printer.SetIndent( 0 );
- doc->Accept( &printer );
- char content[512] = {0};
- int size = printer.Size();
- assert( size < sizeof(content) );
- memcpy( content, printer.CStr(), printer.Size() );
- delete doc;
- }
3.TinyXml 保存时如何处理缩进和行结尾
1) 处理缩进:
a. 如果是保存文件,TinyXML 默认用4个空格做为缩进,根据节点的深度不同,缩进为4个空格的倍数,如果想去掉缩进,需要查找 TinyXML 源文件中所有写4个空格的地方(一共是5处),注释掉或换成你想要的缩进字符,也可以对 TinyXML 做一个改进,增加一个函数用于设置缩进字符,可以设为NULL,即无缩进。
b. 如果是保存到内存中,在 TiXmlPrinter 中有一个函数:SetIndent(),可以设置缩进字符,也可以设为 NULL。
2) 处理行结尾:
a. 如果是保存文件,TinyXML 会在每行的结尾用fprintf()写一个 '\n',在 Windows 上,fprintf 写入文件的 '\n' 都会被转换为 "\r\n"。
b. 如果是保存到内存中,在 TiXmlPrinter 中有一个函数:SetLineBreak(),可以设置行结尾字符,也可以设为 NULL。
- 如何 操作在内存中 xml 格式的内容
- 如何使用 TinyXML 在内存中操作 xml 格式的内容
- 如何使用 TinyXML 在内存中操作 xml 格式的内容
- 如何使用 TinyXML 在内存中操作 xml 格式的内容
- 类中内容在内存中到底是如何分配的呢?
- C语言的各种数据在内存中如何存储?
- java String 在内存中如何存储的?
- float类型数据在内存中如何存储的?
- 细看代码在内存中如何存储
- 进程在内存中如何表示
- 列存储在内存中如何管理
- 整型数据在内存中如何存储?
- -128在内存中如何存储
- 汇编中 ds,ss,cs内容在内存中存放的顺序
- c语言如何操作内存(数据类型、函数在内存中解析简介)
- c语言如何操作内存(数据类型、函数在内存中解析简介)
- 定义unsigned char型指针读取变量在内存中每个字节的内容
- vs2008、vs2010、vs2012中查看变量在内存中的内容的方法
- 新手给视频加字幕 包括制作字幕文件
- 背包问题九讲
- ORA-27101 ORA-01034
- nyist 26 孪生素数问题(筛选法)
- android JNI bridge ----- native和java世界的红娘 (施工中)
- 如何 操作在内存中 xml 格式的内容
- 网络受限下,使用Nexus要解决的两个问题
- 我是这样给自己程序留的“后门”
- 网站书店小项目
- MTK Android 开发编译环境准备
- Java学习笔记——第一天
- android线程状态
- 类和对象
- 项目一:利用成员函数对复数类重载运算符,能用于复数加减乘除