C/C++利用libxml2高效输出XML大文件详解
前言
Libxml2是一个xmlc语言版的解析器,本来是为Gnome项目开发的工具,是一个基于MITLicense的免费开源软件。它除了支持c语言版以外,还支持c++、PHP、Pascal、Ruby、Tcl等语言的绑定,能在Windows、Linux、Solaris、MacOsX等平台上运行。功能还是相当强大的,相信满足一般用户需求没有任何问题。
libxml2常用数据类型
xmlChar是libxml2中的字符类型,在库中的所有字符,字符串都是基于这个数据类型的。
xmlChar*是指针类型,很多函数都会返回一个动态分配的内存的xmlChar*类型的变量,因此,在使用这类函数时要记得释放内存,否则会导致内存泄漏,例如这样的用法:
xmlChar*name=xmlNodeGetContent(CurNode); strcpy(data.name,name); xmlFree(name);
- xmlDoc、xmlDocPtr//文档对象结构体及指针
- xmlNode、xmlNodePtr//节点对象结构体及节点指针
- xmlAttr、xmlAttrPtr//节点属性的结构体及其指针
- xmlNs、xmlNsPtr//节点命名空间的结构及指针
- BAD_CAST//一个宏定义,事实上它即是xmlChar*类型
场景
1.libxml2基本上算是xml的C/C++标准读写库.在linux,macOS里是默认支持.可惜在Windows上有自己专有的msxml,所以并不支持libxml2,恶心的是msxml还不是标配,还要必须另外下载安装,所以作为Windows上优先选择的XML库,就是可跨平台的libxml2.
2.xml的sax读取库expat也是比较优秀的选择,可惜不支持写.
3.一般的写库方式是生成一整个DOM结构,之后把这个DOM结构输出到XML格式的文本里,可调用自带写函数或标准io函数.这样的缺点是如果生成这个DOM结构过于大,会导致在生成这个DOM结构时内存暴涨,之后再输出到内存里,这时候内存又暴涨一次,最后从内存输出到文件里.
说明
1.DOM结构存储非常浪费内存,如果数据量大时,但是元素的父子关系,文本值,属性值等等很浪费内存.如果我们可以按照每个元素来输出的话,最好输出完就释放元素内存,那么能最大限度的利用内存资源.
2.局部输出元素可以最大限度使用系统的资源,比如IO输出需要权限限制的函数,或者输出到界面等
例子
以下例子是windows上使用libxml2,用mingw编译出的libxml2,使用_wfopen来打开unicode编码的文件路径.
#include"stdafx.h" #include#include #include #include #include voidTestStandardIOForXml() { xmlDocPtrdoc=NULL;/*documentpointer*/ xmlNodePtrone_node=NULL,node=NULL,node1=NULL;/*nodepointers*/ charbuff[256]; inti,j; doc=xmlNewDoc(BAD_CAST"1.0"); std::shared_ptr sp_doc(doc,[](void*doc1){ xmlDocPtrdoc=(xmlDocPtr)doc1; xmlFreeDoc(doc); }); FILE*file=_wfopen(L"test.xml",L"wb"); if(!file) return; std::shared_ptr sp_file(file,[](FILE*file){ fclose(file); }); //写XML的声明 xmlChar*doc_buf=NULL; intsize=0; xmlDocDumpMemoryEnc(doc,&doc_buf,&size,"UTF-8"); std::shared_ptr sp_xc(doc_buf,[](xmlChar*doc_buf){ xmlFree(doc_buf); }); fwrite(doc_buf,strlen((constchar*)doc_buf),1,file); xmlBufferPtrbuf=xmlBufferCreate(); std::shared_ptr sp_buf(buf,[](void*buf1){ xmlBufferPtrbuf=(xmlBufferPtr)buf1; xmlBufferFree(buf); }); constchar*kRootBegin=" "; fwrite(kRootBegin,strlen(kRootBegin),1,file); for(inti=0;i<10;++i){ one_node=xmlNewNode(NULL,BAD_CAST"one"); xmlNewChild(one_node,NULL,BAD_CAST"node1", BAD_CAST"contentofnode1"); xmlNewChild(one_node,NULL,BAD_CAST"node2",NULL); node=xmlNewChild(one_node,NULL,BAD_CAST"node3",BAD_CAST"thisnodehasattributes"); xmlNewProp(node,BAD_CAST"attribute",BAD_CAST"yes"); xmlNewProp(node,BAD_CAST"foo",BAD_CAST"bar"); node=xmlNewNode(NULL,BAD_CAST"node4"); node1=xmlNewText(BAD_CAST"otherwaytocreatecontent(whichisalsoanode)"); xmlAddChild(node,node1); xmlAddChild(one_node,node); xmlNodeDump(buf,doc,one_node,1,1); fwrite(buf->content,buf->use,1,file); xmlUnlinkNode(one_node); xmlFreeNode(one_node); xmlBufferEmpty(buf); } constchar*kRootEnd=" "; fwrite(kRootEnd,strlen(kRootEnd),1,file); }
输出文件:
contentÖÐÎÄofnode1 thisnodehasattributes otherwaytocreatecontent(whichisalsoanode) contentofnode1 thisnodehasattributes otherwaytocreatecontent(whichisalsoanode) contentofnode1 thisnodehasattributes otherwaytocreatecontent(whichisalsoanode) contentofnode1 thisnodehasattributes otherwaytocreatecontent(whichisalsoanode) contentofnode1 thisnodehasattributes otherwaytocreatecontent(whichisalsoanode) contentofnode1 thisnodehasattributes otherwaytocreatecontent(whichisalsoanode) contentofnode1 thisnodehasattributes otherwaytocreatecontent(whichisalsoanode) contentofnode1 thisnodehasattributes otherwaytocreatecontent(whichisalsoanode) contentofnode1 thisnodehasattributes otherwaytocreatecontent(whichisalsoanode) contentofnode1 thisnodehasattributes otherwaytocreatecontent(whichisalsoanode)
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。