本文简单介绍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
- xmlTextReaderPtr reader;
- reader = xmlNewTextReaderFilename(xmlfile);
2、从内存建立reader
-
- xmlTextReaderPtr reader;
- reader = xmlReaderForMemory(memory, size, NULL, "UTF-8", 0);
从上述代码来看,建立一个reader是非常容易的。
3、从reader中读数据
建立了reader之后,我们就可以通过reader的辅助函数来实现xml数据的读取。在这里,我讲述的是如何读一个文本方式的XML,并没有使用XML的专有模型。这种方式最原始,也是最容易理解的。
要读一个reader中的数据,使用xmlTextReaderRead来读一个元素,XML中的每一个元素都会经过reader依次读取,我们可以根据需要来检查当前reader位置的元素类型,并取出数据为已所用,当然还要释放由reader分配的数据空间。下面来看一下读的例子:
- ret = xmlTextReaderRead(reader);
- if (ret == 0) return 0;
- if (ret != 1) return -2;
- element = xmlTextReaderName(reader);
-
- if (element != NULL)
- {
- ntype = xmlTextReaderNodeType(reader);
- if (strcmp((const char*) element, "param-name") == 0)
- {
- xmlFree(element);
- if (XML_READER_TYPE_ELEMENT == ntype)
- {
-
- }
- }
- }
xmlTextReaderRead需要一个参数,就是我们前面进行的一个文本读取器指针,该函数返回1表示成功读取,0表示到达文件尾。当成功读取时,可能使用xmlTextReaderName读取当前位置的元素数据,并可以通过xmlTextTextReaderNodeType来读取XML元素的类型。
-
-
-
-
-
- typedef enum {
- XML_READER_TYPE_NONE = 0,
- XML_READER_TYPE_ELEMENT = 1,
- XML_READER_TYPE_ATTRIBUTE = 2,
- XML_READER_TYPE_TEXT = 3,
- XML_READER_TYPE_CDATA = 4,
- XML_READER_TYPE_ENTITY_REFERENCE = 5,
- XML_READER_TYPE_ENTITY = 6,
- XML_READER_TYPE_PROCESSING_INSTRUCTION = 7,
- XML_READER_TYPE_COMMENT = 8,
- XML_READER_TYPE_DOCUMENT = 9,
- XML_READER_TYPE_DOCUMENT_TYPE = 10,
- XML_READER_TYPE_DOCUMENT_FRAGMENT = 11,
- XML_READER_TYPE_NOTATION = 12,
- XML_READER_TYPE_WHITESPACE = 13,
- XML_READER_TYPE_SIGNIFICANT_WHITESPACE = 14,
- XML_READER_TYPE_END_ELEMENT = 15,
- XML_READER_TYPE_END_ENTITY = 16,
- XML_READER_TYPE_XML_DECLARATION = 17
- } xmlReaderTypes;
reader支持如上类型,我们可以根据当前类型来读取数据,因为不现的类型,读取数据的方式不同,比如xmlTextReaderReadString只能读元素(XML_READER_TYPE_ELEMENT)的名称或者文件类型(XML_READER_TYPE_TEXT)的数据。注意一点就是reader是按顺序读取每一个元素,在写代码时,应该不要假定后面一定是什么元素或者特定类型,应该去检测,保证软件的稳定性。
使用xmlTextReaderReadString返回一个元素(xmlChar*类型)时,该区域是由库分配的内存区域,需要使用xmlFree来释放,不然就有内存泄漏。
4、读xml的reader的释放与清理
笔者使用如下方式释放reader
- xmlTextReaderClose(reader);
- xmlFreeTextReader(reader);
- xmlDictCleanup();
- xmlCleanupParser();
- xmlMemoryDump();
- xmlCleanupCharEncodingHandlers();
有一个xmlTextReaderClose函数,当使用该函数时,要注意顺序,一定要在xmlFreeTextReader之前,不然就会出现错误。
二、使用libxml2写xml
写xml文件要比读要来得容易,因为不需要考虑其它可能的因素。
1、写xml文件
- xmlTextWriterPtr writer;
- writer = xmlNewTextWriterFilename(xmlfile, 0);
2、写xml到内存空间
- xmlBufferPtr xmlBuf = xmlBufferCreate();
- if (xmlBuf == NULL) return -2;
- xmlTextWriterPtr writer;
- writer = xmlNewTextWriterMemory(xmlBuf, 0);
2、写xml数据到writer
写xml数据到writer是使用xmlTextWriterXXXXX的函数,具体可参考libxml提供的帮助文档。
在这里我介绍几个常用的函数:
xmlTextWriterStartDocument --- 写一个XML文档的头,可以指定文档的编码格式
xmlTextWriterEndDocument --- 结束一个XML文档
以上两个函数应该成对出现,后续的函数同样也需要成对出现,因为这是XML的规范。
xmlTextWriterStartElement ---- 写开始元素 ---》<开始元素>
xmlTextWriterEndElement ---- 写结束元素 ---》</结束元素>
也可以使如下函数实现一次性写入
xmlTextWriterWriteElement ---- 写元素,包含数据 <开始元素>数据</结束元素>
三、关于libxml2处理中文问题,我将在下一篇的博文中继续。
附hashxml的读数据处理的部分代码:
- int processitemnode(xmlTextReaderPtr reader, sht_hash_table_t *phash)
- {
- if (reader == NULL || phash == NULL) return -1;
- xmlChar* element;
- char *p_k, *p_d;
-
- int ret;
- bool bParam, bValue;
- bParam = bValue = false;
- int ntype;
-
-
-
-
- while (true)
- {
- ret = xmlTextReaderRead(reader);
- if (ret == 0) return 0;
- if (ret != 1) return -2;
- element = xmlTextReaderName(reader);
-
-
- if (element != NULL)
- {
- ntype = xmlTextReaderNodeType(reader);
- if (strcmp((const char*) element, "param-name") == 0)
- {
- xmlFree(element);
- if (XML_READER_TYPE_ELEMENT == ntype)
- {
-
- ret = xmlTextReaderRead(reader);
- if (ret == 0) return 0;
- if (ret != 1) return -2;
- ntype = xmlTextReaderNodeType(reader);
- if (XML_READER_TYPE_TEXT == ntype){
- element = xmlTextReaderReadString(reader);
- if (element == NULL) return -2;
- p_k = ConvertFrom(element, ENCODING);
- xmlFree(element);
- }else{
- p_d = ConvertFrom(BAD_CAST "", ENCODING);
- }
- }
- if(XML_READER_TYPE_END_ELEMENT == ntype)
- {
- bParam = true;
- }
- }
- else if (strcmp((const char*) element, "param-value") == 0)
- {
- xmlFree(element);
- if (XML_READER_TYPE_ELEMENT == ntype)
- {
-
- ret = xmlTextReaderRead(reader);
- if (ret == 0) return 0;
- if (ret != 1) return -2;
- ntype = xmlTextReaderNodeType(reader);
- if (XML_READER_TYPE_TEXT == ntype){
- element = xmlTextReaderReadString(reader);
- if (element == NULL) return -2;
- p_d = ConvertFrom(element, ENCODING);
- xmlFree(element);
- }else{
- p_d = ConvertFrom(BAD_CAST"", ENCODING);
- }
- }
- if(XML_READER_TYPE_END_ELEMENT == ntype)
- {
- bValue = true;
- }
- }else{
- xmlFree(element);
- }
- }
- if (bParam && bValue){
- sht_insert(phash, p_d, p_k);
- free(p_k);
- break;
- }
- }
- return 0;
- }