如何使用 TinyXML 在内存中操作 xml 格式的内容
2012-02-21 19:00
645 查看
如何使用 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 内容:
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)不要尝试链接已经被别的结点链接过的指针, 很显然, 这会造成无法估量的麻烦, 不用多说, 大家都懂的.
写法一:
写法二:
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 内容:
<?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 内部才会帮你把动态生成的对象释放掉。
// 参考了 hoyt00 的文章:http://blog.csdn.net/hoyt00/article/details/6769883:
(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。
相关文章推荐
- 如何使用 TinyXML 在内存中操作 xml 格式的内容
- 如何使用 TinyXML 在内存中操作 xml 格式的内容
- 如何使用 TinyXML 在内存中操作 xml 格式的内容
- 如何 操作在内存中 xml 格式的内容
- 如何使用 mallco 函数进行内存的申请来储存字符串,然后将该字符串的内容进行翻转.
- [C#] .NET Core/Standard 1.X 项目中如何使用XmlIgnoreAttribute等标准范围外的内容,兼谈如何解决“violation of security transparency rules failed”(违反安全透明规则失败)异常
- CB使用TINYXML类库进行XML操作
- tinyxml使用:创建XML,遍历打印xml文件 select操作,获取单个节点值,删除节点操作,修改节点操作,增加节点操作
- 用javascript操作xml-->Web设计中如何使用XML数据源对象(转载)
- 如何使用10M的内存读入100M的文件,并且保证在读取过程中可进行删除、修改和增加内容
- 如何使用Javascript正则表达式来格式化XML内容
- C++使用tinyxml来操作DOM对象(以svg格式为例,其他格式都类似操作)
- 使用tinyxml操作xml中的叶节点
- Excel——如何使用VBA操作单元格的格式
- Thinking XML: 使用 Atom 格式连锁新闻及其他内容
- 危险代码:如何使用Unsafe操作内存中的Java类和对象—Part4
- C#小数点输出格式+推荐内容:XML操作和线程学习
- VB Script 如何使用XSD验证XML文档格式
- 简单使用dom4j对xml文件进行输出操作(如何使用dom4j对xml文件进行输出)
- 如何使用Javascript正则表达式来格式化XML内容