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