libxml2的使用

本文简单介绍libxml2库在linux环境下的使用。

关于libxml库的基本使用,在http://xmlsoft.org/网上有文档。该文档对于函数的使用说明并没有很详细的介绍,参考引用几乎没有,想要在C语言中使用该库,看示例是最好的办法。但是当自己需要完成一些复杂的操作时,直接从文档中找到具体实现方法,并正确编码,很也难做到。该库对于内存使用上并没有做过多的表述,从API文档中,并不能知道取得的资源应该如何释放。笔者经过使用该库实现hash表与xml文件之单的转换,取得了一些经验。本文将以源代码方法讲述使用libxml库读写基本的xml文件,关于解析标准xml文件,像DOM模型之类的,就只能仔细查看相关解析器方面的API文档了。本文中关于资源的使用是经过valgrind测试之后,才放心地植入现有系统中。使用libxml库,最好是经过内存泄漏工具做检测,不然很容易出问题的。

我分两部分来介绍我的hashtable与XML文件之间的转换,第一部分,读xml,第二部分,写xml。

一、使用libxml读XML文件

要读xml,需要使用reader,这里介绍两种方式,一种从文件读取,一种从内存读取。其它就是通过libxml库中提供的两个API来建立reader.请看代码:

1、从文件建立reader

[cpp]  view plain copy
  1. xmlTextReaderPtr reader;  
  2. reader = xmlNewTextReaderFilename(xmlfile);  

2、从内存建立reader

[c-sharp]  view plain copy
  1. // char* memory, int size  
  2. xmlTextReaderPtr reader;  
  3. reader = xmlReaderForMemory(memory, size, NULL, "UTF-8", 0);  

从上述代码来看,建立一个reader是非常容易的。

3、从reader中读数据

建立了reader之后,我们就可以通过reader的辅助函数来实现xml数据的读取。在这里,我讲述的是如何读一个文本方式的XML,并没有使用XML的专有模型。这种方式最原始,也是最容易理解的。

要读一个reader中的数据,使用xmlTextReaderRead来读一个元素,XML中的每一个元素都会经过reader依次读取,我们可以根据需要来检查当前reader位置的元素类型,并取出数据为已所用,当然还要释放由reader分配的数据空间。下面来看一下读的例子:

[cpp]  view plain copy
  1. ret = xmlTextReaderRead(reader);  
  2. if (ret == 0) return 0;  
  3. if (ret != 1) return -2;  
  4. element = xmlTextReaderName(reader);  
  5.   
  6. if (element != NULL)  
  7. {  
  8.     ntype = xmlTextReaderNodeType(reader);  
  9.     if (strcmp((const char*) element, "param-name") == 0)  
  10.     {  
  11.         xmlFree(element);  
  12.         if (XML_READER_TYPE_ELEMENT == ntype)  
  13.         {  
  14.         /*......*/  
  15.         }  
  16.     }  
  17. }  

xmlTextReaderRead需要一个参数,就是我们前面进行的一个文本读取器指针,该函数返回1表示成功读取,0表示到达文件尾。当成功读取时,可能使用xmlTextReaderName读取当前位置的元素数据,并可以通过xmlTextTextReaderNodeType来读取XML元素的类型。

[cpp]  view plain copy
  1. /** 
  2.  * xmlReaderTypes: 
  3.  * 
  4.  * Predefined constants for the different types of nodes. 
  5.  */  
  6. typedef enum {  
  7.     XML_READER_TYPE_NONE = 0,  
  8.     XML_READER_TYPE_ELEMENT = 1,  
  9.     XML_READER_TYPE_ATTRIBUTE = 2,  
  10.     XML_READER_TYPE_TEXT = 3,  
  11.     XML_READER_TYPE_CDATA = 4,  
  12.     XML_READER_TYPE_ENTITY_REFERENCE = 5,  
  13.     XML_READER_TYPE_ENTITY = 6,  
  14.     XML_READER_TYPE_PROCESSING_INSTRUCTION = 7,  
  15.     XML_READER_TYPE_COMMENT = 8,  
  16.     XML_READER_TYPE_DOCUMENT = 9,  
  17.     XML_READER_TYPE_DOCUMENT_TYPE = 10,  
  18.     XML_READER_TYPE_DOCUMENT_FRAGMENT = 11,  
  19.     XML_READER_TYPE_NOTATION = 12,  
  20.     XML_READER_TYPE_WHITESPACE = 13,  
  21.     XML_READER_TYPE_SIGNIFICANT_WHITESPACE = 14,  
  22.     XML_READER_TYPE_END_ELEMENT = 15,  
  23.     XML_READER_TYPE_END_ENTITY = 16,  
  24.     XML_READER_TYPE_XML_DECLARATION = 17  
  25. } xmlReaderTypes;  

reader支持如上类型,我们可以根据当前类型来读取数据,因为不现的类型,读取数据的方式不同,比如xmlTextReaderReadString只能读元素(XML_READER_TYPE_ELEMENT)的名称或者文件类型(XML_READER_TYPE_TEXT)的数据。注意一点就是reader是按顺序读取每一个元素,在写代码时,应该不要假定后面一定是什么元素或者特定类型,应该去检测,保证软件的稳定性。

使用xmlTextReaderReadString返回一个元素(xmlChar*类型)时,该区域是由库分配的内存区域,需要使用xmlFree来释放,不然就有内存泄漏。

4、读xml的reader的释放与清理

笔者使用如下方式释放reader

[cpp]  view plain copy
  1. xmlTextReaderClose(reader);  
  2. xmlFreeTextReader(reader);  
  3. xmlDictCleanup();  
  4. xmlCleanupParser();  
  5. xmlMemoryDump();  
  6. xmlCleanupCharEncodingHandlers();  

有一个xmlTextReaderClose函数,当使用该函数时,要注意顺序,一定要在xmlFreeTextReader之前,不然就会出现错误。 

二、使用libxml2写xml

写xml文件要比读要来得容易,因为不需要考虑其它可能的因素。

1、写xml文件

[cpp]  view plain copy
  1. xmlTextWriterPtr writer;  
  2. writer = xmlNewTextWriterFilename(xmlfile, 0);  

2、写xml到内存空间

[cpp]  view plain copy
  1. xmlBufferPtr xmlBuf = xmlBufferCreate();  
  2. if (xmlBuf == NULL) return -2;  
  3. xmlTextWriterPtr writer;  
  4. writer = xmlNewTextWriterMemory(xmlBuf, 0);  

2、写xml数据到writer

写xml数据到writer是使用xmlTextWriterXXXXX的函数,具体可参考libxml提供的帮助文档。

在这里我介绍几个常用的函数:

xmlTextWriterStartDocument  --- 写一个XML文档的头,可以指定文档的编码格式

xmlTextWriterEndDocument    --- 结束一个XML文档

以上两个函数应该成对出现,后续的函数同样也需要成对出现,因为这是XML的规范。

xmlTextWriterStartElement     ---- 写开始元素   ---》<开始元素>

xmlTextWriterEndElement       ---- 写结束元素   ---》</结束元素>

也可以使如下函数实现一次性写入

xmlTextWriterWriteElement    ---- 写元素,包含数据 <开始元素>数据</结束元素>

 

三、关于libxml2处理中文问题,我将在下一篇的博文中继续。

 

附hashxml的读数据处理的部分代码:

[c-sharp]  view plain copy
  1. int processitemnode(xmlTextReaderPtr reader, sht_hash_table_t *phash)  
  2. {  
  3.   if (reader == NULL || phash == NULL) return -1;  
  4.   xmlChar* element;  
  5.   char *p_k, *p_d;  
  6.   
  7.   int ret;  
  8.   bool bParam, bValue;  
  9.   bParam = bValue = false;  
  10.   int ntype;  
  11.   
  12.   // 读接下来的每一个节点,如果遇到param-name就读接下来的KEY  
  13.   // 如果遇到param-value就读接下来的DATA  
  14.   // 读完了就插入HASH表,并返回  
  15.   while (true)  
  16.     {  
  17.         ret = xmlTextReaderRead(reader);  
  18.         if (ret == 0) return 0;  
  19.         if (ret != 1) return -2;  
  20.         element = xmlTextReaderName(reader);  
  21.   
  22.   
  23.         if (element != NULL)  
  24.         {  
  25.             ntype = xmlTextReaderNodeType(reader);  
  26.             if (strcmp((const char*) element, "param-name") == 0)  
  27.             {  
  28.                 xmlFree(element);  
  29.                 if (XML_READER_TYPE_ELEMENT == ntype)  
  30.                 {  
  31.                     // 读KEY  
  32.                     ret = xmlTextReaderRead(reader);  
  33.                     if (ret == 0) return 0;  
  34.                     if (ret != 1) return -2;  
  35.                     ntype = xmlTextReaderNodeType(reader);  
  36.                     if (XML_READER_TYPE_TEXT == ntype){  
  37.                         element = xmlTextReaderReadString(reader);  
  38.                         if (element == NULL) return -2;  
  39.                         p_k = ConvertFrom(element, ENCODING);  
  40.                         xmlFree(element);  
  41.                     }else{  
  42.                         p_d = ConvertFrom(BAD_CAST "", ENCODING);  
  43.                     }  
  44.                 }  
  45.                 if(XML_READER_TYPE_END_ELEMENT == ntype)  
  46.                 {  
  47.                     bParam = true;  
  48.                 }  
  49.             }  
  50.             else if (strcmp((const char*) element, "param-value") == 0)  
  51.             {  
  52.                 xmlFree(element);  
  53.                 if (XML_READER_TYPE_ELEMENT == ntype)  
  54.                 {  
  55.                     // 读DATA  
  56.                     ret = xmlTextReaderRead(reader);  
  57.                     if (ret == 0) return 0;  
  58.                     if (ret != 1) return -2;  
  59.                     ntype = xmlTextReaderNodeType(reader);  
  60.                     if (XML_READER_TYPE_TEXT == ntype){  
  61.                         element = xmlTextReaderReadString(reader);  
  62.                         if (element == NULL) return -2;  
  63.                         p_d = ConvertFrom(element, ENCODING);  
  64.                         xmlFree(element);  
  65.                     }else{  
  66.                         p_d = ConvertFrom(BAD_CAST"", ENCODING);  
  67.                     }  
  68.                 }  
  69.                 if(XML_READER_TYPE_END_ELEMENT == ntype)  
  70.                 {  
  71.                     bValue = true;  
  72.                 }  
  73.             }else{  
  74.                 xmlFree(element);  
  75.             }  
  76.         }  
  77.         if (bParam && bValue){  
  78.             sht_insert(phash, p_d, p_k);  
  79.             free(p_k);  
  80.             break;  
  81.         }  
  82.     }  
  83.   return 0;  
  84. }  

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值