C/C++利用libxml2高效輸出XML大文件詳解
前言
Libxml2 是一個(gè)xml c語言版的解析器,本來是為Gnome項(xiàng)目開發(fā)的工具,是一個(gè)基于MIT License的免費(fèi)開源軟件。它除了支持c語言版以外,還支持c++、PHP、Pascal、Ruby、Tcl等語言的綁定,能在Windows、Linux、Solaris、MacOsX等平臺(tái)上運(yùn)行。功能還是相當(dāng)強(qiáng)大的,相信滿足一般用戶需求沒有任何問題。
libxml2常用數(shù)據(jù)類型
xmlChar是libxml2中的字符類型,在庫中的所有字符,字符串都是基于這個(gè)數(shù)據(jù)類型的。
xmlChar*是指針類型,很多函數(shù)都會(huì)返回一個(gè)動(dòng)態(tài)分配的內(nèi)存的xmlChar*類型的變量,因此,在使用這類函數(shù)時(shí)要記得釋放內(nèi)存,否則會(huì)導(dǎo)致內(nèi)存泄漏,例如這樣的用法:
xmlChar *name = xmlNodeGetContent(CurNode); strcpy(data.name, name); xmlFree(name);
- xmlDoc、 xmlDocPtr //文檔對(duì)象結(jié)構(gòu)體及指針
- xmlNode、 xmlNodePtr //節(jié)點(diǎn)對(duì)象結(jié)構(gòu)體及節(jié)點(diǎn)指針
- xmlAttr、 xmlAttrPtr //節(jié)點(diǎn)屬性的結(jié)構(gòu)體及其指針
- xmlNs、 xmlNsPtr //節(jié)點(diǎn)命名空間的結(jié)構(gòu)及指針
- BAD_CAST //一個(gè)宏定義,事實(shí)上它即是xmlChar*類型
場(chǎng)景
1.libxml2基本上算是xml的C/C++標(biāo)準(zhǔn)讀寫庫. 在linux,macOS里是默認(rèn)支持. 可惜在Windows上有自己專有的msxml, 所以并不支持libxml2, 惡心的是msxml還不是標(biāo)配, 還要必須另外下載安裝, 所以作為Windows上優(yōu)先選擇的XML庫, 就是可跨平臺(tái)的libxml2.
2.xml的sax讀取庫expat也是比較優(yōu)秀的選擇, 可惜不支持寫.
3.一般的寫庫方式是生成一整個(gè)DOM結(jié)構(gòu), 之后把這個(gè)DOM結(jié)構(gòu)輸出到XML格式的文本里, 可調(diào)用自帶寫函數(shù)或標(biāo)準(zhǔn)io函數(shù). 這樣的缺點(diǎn)是如果生成這個(gè)DOM結(jié)構(gòu)過于大, 會(huì)導(dǎo)致在生成這個(gè)DOM結(jié)構(gòu)時(shí)內(nèi)存暴漲,之后再輸出到內(nèi)存里,這時(shí)候內(nèi)存又暴漲一次,最后從內(nèi)存輸出到文件里.
說明
1.DOM結(jié)構(gòu)存儲(chǔ)非常浪費(fèi)內(nèi)存, 如果數(shù)據(jù)量大時(shí), 但是元素的父子關(guān)系, 文本值,屬性值等等很浪費(fèi)內(nèi)存. 如果我們可以按照每個(gè)元素來輸出的話,最好輸出完就釋放元素內(nèi)存, 那么能最大限度的利用內(nèi)存資源.
2.局部輸出元素可以最大限度使用系統(tǒng)的資源, 比如IO輸出需要權(quán)限限制的函數(shù), 或者輸出到界面等
例子
以下例子是windows上使用libxml2, 用mingw編譯出的libxml2, 使用_wfopen來打開unicode編碼的文件路徑.
#include "stdafx.h"
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlreader.h>
#include <iostream>
#include <memory>
void TestStandardIOForXml()
{
xmlDocPtr doc = NULL; /* document pointer */
xmlNodePtr one_node = NULL, node = NULL, node1 = NULL;/* node pointers */
char buff[256];
int i, j;
doc = xmlNewDoc(BAD_CAST "1.0");
std::shared_ptr<void> sp_doc(doc,[](void* doc1){
xmlDocPtr doc = (xmlDocPtr)doc1;
xmlFreeDoc(doc);
});
FILE* file = _wfopen(L"test.xml",L"wb");
if(!file)
return;
std::shared_ptr<FILE> sp_file(file,[](FILE* file){
fclose(file);
});
// 寫XML的聲明
xmlChar* doc_buf = NULL;
int size = 0;
xmlDocDumpMemoryEnc(doc,&doc_buf,&size,"UTF-8");
std::shared_ptr<xmlChar> sp_xc(doc_buf,[](xmlChar* doc_buf){
xmlFree(doc_buf);
});
fwrite(doc_buf,strlen((const char*)doc_buf),1,file);
xmlBufferPtr buf = xmlBufferCreate();
std::shared_ptr<void> sp_buf(buf,[](void* buf1){
xmlBufferPtr buf = (xmlBufferPtr)buf1;
xmlBufferFree(buf);
});
const char* kRootBegin = "<ROOT>";
fwrite(kRootBegin,strlen(kRootBegin),1,file);
for(int i = 0; i< 10; ++i){
one_node = xmlNewNode(NULL, BAD_CAST "one");
xmlNewChild(one_node, NULL, BAD_CAST "node1",
BAD_CAST "content of node 1");
xmlNewChild(one_node, NULL, BAD_CAST "node2", NULL);
node = xmlNewChild(one_node, NULL, BAD_CAST "node3",BAD_CAST "this node has attributes");
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 "other way to create content (which is also a node)");
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);
}
const char* kRootEnd = "</ROOT>";
fwrite(kRootEnd,strlen(kRootEnd),1,file);
}
輸出文件:
<?xml version="1.0" encoding="UTF-8"?> <ROOT><one> <node1>contentÖÐÎÄ of node 1</node1> <node2/> <node3 attribute="yes" foo="bar">this node has attributes</node3> <node4>other way to create content (which is also a node)</node4> </one><one> <node1>content of node 1</node1> <node2/> <node3 attribute="yes" foo="bar">this node has attributes</node3> <node4>other way to create content (which is also a node)</node4> </one><one> <node1>content of node 1</node1> <node2/> <node3 attribute="yes" foo="bar">this node has attributes</node3> <node4>other way to create content (which is also a node)</node4> </one><one> <node1>content of node 1</node1> <node2/> <node3 attribute="yes" foo="bar">this node has attributes</node3> <node4>other way to create content (which is also a node)</node4> </one><one> <node1>content of node 1</node1> <node2/> <node3 attribute="yes" foo="bar">this node has attributes</node3> <node4>other way to create content (which is also a node)</node4> </one><one> <node1>content of node 1</node1> <node2/> <node3 attribute="yes" foo="bar">this node has attributes</node3> <node4>other way to create content (which is also a node)</node4> </one><one> <node1>content of node 1</node1> <node2/> <node3 attribute="yes" foo="bar">this node has attributes</node3> <node4>other way to create content (which is also a node)</node4> </one><one> <node1>content of node 1</node1> <node2/> <node3 attribute="yes" foo="bar">this node has attributes</node3> <node4>other way to create content (which is also a node)</node4> </one><one> <node1>content of node 1</node1> <node2/> <node3 attribute="yes" foo="bar">this node has attributes</node3> <node4>other way to create content (which is also a node)</node4> </one><one> <node1>content of node 1</node1> <node2/> <node3 attribute="yes" foo="bar">this node has attributes</node3> <node4>other way to create content (which is also a node)</node4> </one></ROOT>
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
與ASCII碼相關(guān)的C語言字符串操作函數(shù)
這篇文章主要介紹了與ASCII碼相關(guān)的C語言字符串操作函數(shù),分別是將字符轉(zhuǎn)換為ASCII碼的toascii()函數(shù)和根據(jù)ASCII碼進(jìn)行字符串比較的strcoll()函數(shù),需要的朋友可以參考下2015-08-08
C++ 關(guān)于STL中sort()對(duì)struct排序的方法
本篇文章介紹了,關(guān)于STL中sort()對(duì)struct排序的方法。需要的朋友參考下2013-04-04
java 出現(xiàn)NullPointerException的原因及解決辦法
這篇文章主要介紹了java 出現(xiàn)NullPointerException的原因及解決辦法的相關(guān)資料,這里說明出現(xiàn)NullPointerException 的原因的總結(jié),并說明該如何解決,需要的朋友可以參考下2017-08-08
vscode遠(yuǎn)程連接服務(wù)器(免密登錄+遠(yuǎn)程開發(fā))
vscode的遠(yuǎn)程連接功能十分方便,本文就來介紹一下vscode遠(yuǎn)程連接服務(wù)器,主要包括免密登錄和遠(yuǎn)程開發(fā),感興趣的可以了解一下2024-07-07
在std::thread中創(chuàng)建并管理QEventLoop的全面解析
QEventLoop的工作原理可以簡單地理解為一個(gè)無限循環(huán),它會(huì)不斷地檢查是否有新的事件需要處理,如果有,就將事件從事件隊(duì)列中取出,然后找到相應(yīng)的事件處理器進(jìn)行處理,這篇文章主要介紹了在std::thread中創(chuàng)建并管理QEventLoop的全面指南,需要的朋友可以參考下2023-06-06

