在xml里追加结点时添加回车(libxml2)

标签:
clibxml2linux杂谈 |
10http://www.cppblog.com/Images/OutliningIndicators/None.gif
11http://www.cppblog.com/Images/OutliningIndicators/None.gif
12http://www.cppblog.com/Images/OutliningIndicators/None.gif
13http://www.cppblog.com/Images/OutliningIndicators/None.gif
14http://www.cppblog.com/Images/OutliningIndicators/None.gif
15http://www.cppblog.com/Images/OutliningIndicators/None.gif
16http://www.cppblog.com/Images/OutliningIndicators/None.gif
17http://www.cppblog.com/Images/OutliningIndicators/None.gif
18http://www.cppblog.com/Images/OutliningIndicators/None.gif
19http://www.cppblog.com/Images/OutliningIndicators/None.gif
20http://www.cppblog.com/Images/OutliningIndicators/None.gif
21http://www.cppblog.com/Images/OutliningIndicators/None.gif</BODY>
例如,使用该文章例子中的代码在上面的filesystem节点的最后插入一个keyword的子结点后的,
该xml文件的表示如下:
10http://www.cppblog.com/Images/OutliningIndicators/None.gif
11http://www.cppblog.com/Images/OutliningIndicators/None.gif
12http://www.cppblog.com/Images/OutliningIndicators/None.gif
13http://www.cppblog.com/Images/OutliningIndicators/None.gif
14http://www.cppblog.com/Images/OutliningIndicators/None.gif
15http://www.cppblog.com/Images/OutliningIndicators/None.gif
16http://www.cppblog.com/Images/OutliningIndicators/None.gif
17http://www.cppblog.com/Images/OutliningIndicators/None.gif
18http://www.cppblog.com/Images/OutliningIndicators/None.gif
19http://www.cppblog.com/Images/OutliningIndicators/None.gif
20http://www.cppblog.com/Images/OutliningIndicators/None.gif
21http://www.cppblog.com/Images/OutliningIndicators/None.gif</BODY>
你会发现keyword和/filesystem像下面那样被挤在一起了,这并不是我们想要的.
<keyword1>hello</keyword1><keyword2>hello</keyword2><keyword3>hello</keyword3></filesystem>
通过设定 xmlKeepBlanksDefault(0) 以及
xmlSaveFormatFile(...)的format参数设置成1,都无法实现
在新追加的结点后面添加回车换行。
在www.xmlsoft.org的官方网站的maillist里关于这方面的信息非常少。但是,对我帮助最大还是
http://mail.gnome.org/archives/xml/2007-May/msg00043.html
属性的时候用的xmlReadFile函数,而且options参数设定的是XML_PARSE_NOBLANKS。
于是,我们用xmlReadFile(...),把它的options参数设定成XML_PARSE_NOBLANKS后,就可以自动添加
回车了。
那,重新修正了的例子程序是如下那样,里面只修改了两条语句。
1http://www.cppblog.com/Images/OutliningIndicators/None.gif#include
13http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif}
14http://www.cppblog.com/Images/OutliningIndicators/None.gif
15http://www.cppblog.com/Images/OutliningIndicators/None.gifxmlDocPtr
16http://www.cppblog.com/Images/OutliningIndicators/None.gifparseDoc
17{
18http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
21http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
22http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
24http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
25http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
27http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
{
30http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
31http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
34http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
35http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif
36http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
37http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
40http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
41http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
43http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
44http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif
45http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
47http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
48http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif
49http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
51http://www.cppblog.com/Images/OutliningIndicators/None.gif
52http://www.cppblog.com/Images/OutliningIndicators/None.gifint
53http://www.cppblog.com/Images/OutliningIndicators/None.gifmain
54{
55http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
56http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
57http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
59http://www.cppblog.com/Images/OutliningIndicators/ContractedSubBlock.gif {
60http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
61http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
62http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif
63http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
64http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
65http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
{
68http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
69http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
70http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
72http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
73http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif}
修正1:是把xmlParseFile替换成xmlReadFile,并且是options参数设定成XML_PARSE_NOBLANKS;否则的话是不会在结点后面添加回车的。
修正2:把xmlSaveFormatFile的format参数修改成1,否则在使用xmlReadFile打开的xml文件时,在生成的xml文件里是会把所有的结点都放到一行里显示。
另外:xmlKeepBlanksDefault(0)
除了在读入xml文件时忽略空白之外,还会在写出xml文件时在每行前面放置缩进(indent)。如果使用xmlKeepBlanksDefault(1)
则你会发现每行前面的缩进就没有了,但不会影响回车换行。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
额外话题: 更新结点的值得时候segement
fault错误
下面的代码是更新XML文件里的某些结点元素的值的简单的例子。
1http://www.cppblog.com/Images/OutliningIndicators/None.gif
{
{
11http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
12http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockEnd.gif
运行该段代码,有时候会在使用libxml2的API函数xmlNodeSetContent
处发生段错误,但不是100%发生。
只有该结点在原来值是某些字符串的时候会发生该错误,比如说,
原来的值是"zo"的时候就会让程序崩溃。
阅读了libxml2的源代码发现,xmlNodeSetContent函数,在把结点值
设置成新的字符串之前会调用xmlFree(cur->content)来释放掉原来
字符串缓冲区的内存。
xmlNodeSetContent函数的代码片断:
1http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
16http://www.cppblog.com/Images/dot.gif{
17http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
18http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
19http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif
20http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif
在上面代码里,如果结点值得字符串如果在libxml2的字典缓冲区(cur->doc->dict)里,
就把该字符串释放掉。而原来的字符串"zo"恰好在它的字典缓冲里,那这样传递到
xmlFree函数里的地址是冲区的一部分而不是缓冲区的首地址的话,free函数当然
会死掉了。如果换成其他的字符串就没有任何问题。
但是,令人不解的是在libxml2的另一部分代码里,删除节点的程序去不是这样做。
例如,在一个结点被删除后,通常会使用xmlFreeDoc函数来释放该结点,恰好在这段
代码里却是判断如果该字符串不再字典缓冲区才去释放它,也就是调用宏DICT_FREE
来完成释放工作,这儿正好与前面的相反,很难理解为什么会产生矛盾。
宏DICT_FREE的代码:
10http://www.cppblog.com/Images/OutliningIndicators/None.gif
11http://www.cppblog.com/Images/OutliningIndicators/None.gif
在考虑这是否是xmlNodeSetContent函数的bug,不过在maillist和bugzilla也没有翻到关于它
的任何说明。
开发时间上也不允许去跟libxml2深究它是否是bug,只要采用了迂回策略了。
想办法不让libxml2产生字典缓冲不就可以了吗。
通过官方手册我们可以知道,xmlReadFile函数可以附加XML_PARSE_NODICT选项
来避免产生字典缓冲。就像下面这样:
doc
这样的话,最开始的那段程序运行起来就没有任何问题了。