張沖
摘 要:XML是一種僅基于普通文本卻可以實現任何兩個應該程序間的數據共享的文本語言。本文在簡單介紹XML的基礎上,通過c++解析器Tingxml實現c++對多值多屬性XML文件的讀取和存儲,并對Tingxml解析器在ASCII(多字節(jié)字符集)項目中讀取XML過程中出現的不支持中文字符問題進行解決。
關鍵詞:XML;Tingxml;中文字符;STL
1 XML簡介
可擴展性標記語言(Extensible Markup Language,簡稱XML)是W3C(World Wide Web Consortium)定義的一種程序間數據傳輸和交換的標準語言,為不同應用程序間的數據傳輸和交換提供了一種簡單的方法[1]。XML獨立于任何語言和體系結構,是一種靈活的不局限于任何特定模式的半結構化文本數據,無需顧慮格式,只要求標簽的成對出現并按照樹狀結構存儲即可,所以能很好的表達數據本身,適合進行數據的存儲和傳遞,可以用來描述各種復雜信息。
2 C++XML解析器(Tingxml)
XML的解析技術作為其應用的基礎,一直是XML的研究熱點[2]。由于c++中本身未包含解析XML的函數庫,所以當c++需要對XML進行解析時常使用c++XML解析器來完成。
本文主要介紹基于Tingxml解析器的c++XML解析,Tingxml是一個基于DOM模型的輕量級XML解析器,其模型通過解析XML,在內存中生成DOM模型,將整個文檔分成多個元素(如書、章、節(jié)、段等),并利用樹型結構表示這些元素之間的順序關系以及嵌套包含關系,從而讓我們很方便的遍歷這棵XML樹。
整個Tingxml解析庫的構成主要由DOM模型類和操作類構成。DOM模型類包括:TiXMLBase(模型基類)、TiXMLAttribute(元素屬性類)、TiXMLNode(應用于DOM結構節(jié)點)、TiXMLComment(XML中的注釋類)、TiXMLDeclaration(應用于XML的聲明,即<?versiong="1.0" ?> )、TiXMLDocument(文檔類)、TiXMLElement(元素類)、TiXMLText(文字類)、TiXMLUnknown(應用于XML的位置部分)。操作類主要是TiXMLHandler類,定義了對XML的操作。Tingxml由兩個頭文件(.h文件)和四個CPP文件(.cpp文件)構成,只要將其導入工程就可以使用其進行XML的解析。
3 XML的數據解析
(1)含多種類型數據XML的數據解析
考慮到XML包含數據的多樣性并結合Tingxml解析庫自身的特點,本文利用STL(標準模板庫)中的順序存儲容器(vector)、關聯存儲容器(map)和結構體相互嵌套的方法來對解析得到的數據進行存儲,實現對多值多屬性XML文檔的數據存儲。
STL(標準模板庫)是C++開發(fā)中用于數據存儲所必不可少的函數庫,其中的存儲容器包括:向量(vector);列表(list);集合(set);映射(map)等[3]。
在對XML進行數據解析的時候,基于XML的特性,我們很容易可以想到去使用關聯容器來對解析出來的數據進行存儲。但STL庫中的關聯容器映射(map)中的key/value存儲方式僅能滿足數據名和數據值得存儲,當XML的一個節(jié)點上含有多個屬性和多個值時僅用map是無法滿足使用需要的。為此,本文采用vector、結構體和map相嵌套的方法實現單個節(jié)點含有多個屬性和多個值的XML的解析,并將數據的屬性和值分開存儲以方便使用。具體實現方法如下:
struct arg1//創(chuàng)建一個包含兩個map
{map
map
vector
ReadXML(const char* XMLpath)
{arg1 d_arg;
TiXMLDocument myDocument(XMLpath); //根據路徑獲取整個XML文檔
myDocument.LoadFile();//下載xml文檔
TiXMLElement* rootElement = myDocument.RootElement(); //加載根目錄
TiXMLElement*fileArgsElement=rootElement->FirstChildEle
ment();
//獲取根目錄下的第一個節(jié)點
if(fileArgsElement)
{TiXMLElement* argElement = fileArgsElement->FirstChild
Element();
//獲取該節(jié)點的第一個子節(jié)點
while ( argElement )
{TiXMLAttribute* attributeOffileArge = argElement-
>FirstAttribute();
//獲取該子節(jié)點的第一個屬性
while(attributeOffileArge)
{CString m_attribute,CString m_name;//定義cstring用于存儲屬性值
m_attribute.Format("%s",attributeOffileArge->Value());
m_name.Format("%s",attributeOffileArge->Name());
d_arg.Attributes.insert(pair
(m_name,m_attribute));
attributeOffileArge=attributeOffileArge->Next();}
TiXMLElement* addressElement=argElement-
>FirstChildElement();
//獲取該節(jié)點的第一個值
while(addressElement)
{CString m_value,m_name;//定義cstring用于存儲節(jié)點值信息
m_name.Format("%s",addressElement->Value());
m_value.Format("%s",addressElement->GetText());
d_arg.Values.insert(pair
addressElement=addressElement->NextSiblingElement(); }
Attrus.push_back(d_arg);
argElement=argElement->NextSiblingElement();//指向下一個節(jié)點}}
通過上述代碼可以看到,使用包含兩個map
(2)多字節(jié)字符集項目中含中文符號XML的解析
使用3.1中的方法可以輕松的實現XML文檔的解析,滿足了多個屬性信息和值信息XML的數據存儲,并將節(jié)點的值和屬性分開存放到各自的map中。但是如果經常使用Tingxml的話還會發(fā)現,當在多字節(jié)字符集項目中使用Tingxml時如果解析的數據中含有中文字符,最終的輸出結果將并非你所愿。這是因為Tingxml目前僅直接支持解析UTF-8編碼的XML,而對于多字節(jié)字符集項目, 雖然支持UTF-8, 但卻不能與控件直接交互,必須經過轉換,否則不能支持中文。因此要實現多字節(jié)字符集項目中含中文符號XML的解析,就必須實現字符類型從UTF-8到ANSI的轉換。
本文通過使用WideCharToMultiByte和MultiByteToWideChar轉換函數,結合CP_ACP代碼頁和CP_UTF8代碼頁實現字符從UTF-8到ANSI的轉換。實現方法如下:
CString ConvertUtf8ToGBK(const char* str_UTF8)
{int len = MultiByteToWideChar(CP_UTF8, 0, str_UTF8, -1, NULL, 0);
wchar_t* wsGBK = new wchar_t[len+1];memset(wsGBK, 0, len*2+2);
MultiByteToWideChar(CP_UTF8, 0, str_UTF8, -1, wsGBK, len);//將UTF-8轉換成Unicode
len = WideCharToMultiByte(CP_ACP, 0, wsGBK, -1, NULL, 0, NULL, NULL);
char* sGBK = new char[len+1];memset(sGBK, 0, len+1);
WideCharToMultiByte (CP_ACP, 0, wsGBK, -1, sGBK, len, NULL, NULL);//將ANSI轉換成ANSI
CString str(sGBK);
return str;}
用上述方法將Tingxml解析得到的XML數據字符從UTF-8轉換成ANSI編碼,就可以實現在多字節(jié)字符集項目中使用Tingxml解析含有中文字符的XML了。
3 總結
Tingxml解析庫是XML文檔解析的重要解析庫,c++和Tingxml相結合能夠快速對XML文檔中的數據信息進行解析。但Tingxml自身的特征決定了它在數據存儲和中文字符解析方面的局限性。通過本文方法的使用,我們可以更好的運用Tingxml對XML文檔進行數據解析,實現多值多屬性XML數據存儲和Tingxml對中文字符的解析。
參考文獻:
[1]孫曉非等. XML基礎教程與實驗指導[M].清華大學出版社,2008.
[2]王超,鄭清. C++解析XML方法的研究和實現.電腦與電信,2012.
[3]李普曼(Stanley B.Lippman)等,C++Primer中文版[M].李師賢、蔣愛軍等譯.第4版.北京:人民郵電出版社,2008.