1. 初始化平臺:
XMLPlatformUtils::Initialze()
2. 銷燬平臺:
XMLPlatformUtils::Terminate();
3. 加載分析報文
XercesDOMParser *parser = new XercesDOMParser();
Parser->parse( 參數 ); 這個參數可以直接是文件名,也可以是內存的數據,具體的查看 API
4. 數據格式轉換
XMLString.transcode() 這個方法有多個重載,既可以把 XMLCh * 格式的數據轉換成 char * 的數據,也可以把 char * 的數據轉換成 XMLCh *, 我們也可以利用這個函數來初始化 XMLCh 格式類型的數組,比如 XMLCh temp[100];
XMLString.transcode(“LS”,temp,99);// 用“ LS ”初始化 temp 這個數組的內容。
5. 分析報文後,如何得到文檔的樹型結構
DOMDocument *xmlDoc = parser->getDocument();
6. 得到樹型結構後,如何得到第一個根節點
DOMElement *root = xmlDoc->getDocumentElement();
7. 如何遍歷文檔的結構
遍歷一個樹型的文檔結構有三種方法。
1 .使用 DOMNodeIterator 類
DOMNodeIterator *iterator = xmlDoc->createNodeIterator(root, DOMNodeFilter::SHOW_TEXT, NULL, true);
for ( DOMNode * current = (DOMNode *)iterator->nextNode(); current != 0; current = (DOMNode *)iterator->nextNode() )
{
string strValue = XMLString::transcode(current->getNodeValue());
std::cout <<strValue<<endl;
}// 以上就可以把 xml 文檔中的屬性爲 NODETEXT 節點的內容給打印出來。
2 .使用 DOMTreeWalker 類
D OMTreeWalker *walker = xmlDoc->createTreeWalker(root, DOMNodeFilter::SHOW_TEXT, NULL, true);
f or (DOMNode *current = walker->nextNode(); current != 0; current = walker->nextNode() )
{
char *strValue = XMLString::transcode( current->getNodeValue() ); std::cout <<strValue;
XMLString::release(&strValue);
}
3 .使用子節點直接遍歷樹型結構
DOMNode *n = (DOMNode*)xmlDoc->getDocumentElement();
// 下面開始遍歷這個樹的結構
if(n)
{
if (n->getNodeType() == DOMNode::ELEMENT_NODE)
{
DOMNodeList* nodeList = n->getChildNodes();
unsigned int nListLen = nodeList->getLength();
for (unsigned int i=0; i<nListLen; ++i)
{
DOMNode* nodeTemp = nodeList->item(i);
if (nodeTemp->getNodeType() == DOMNode::ELEMENT_NODE)
{
for (DOMNode* node1=nodeTemp->getFirstChild(); node1!=0; node1=node1->getNextSibling())
{
char* name = XMLString::transcode(node1->getNodeName());
string strTemp = name;
if (strTemp == "name") // 這個就是跟 xml 文檔中 name 節點匹配
{
char* myname=XMLString::transcode(node1->getFirstChild()->getNodeValue());
cout<<myname<<endl;
}
}
}
continue;
}
}
}
8. 如何添加子節點。
//Add new (empty) Element to the root element
DOM_Element parentNode = …;// parent is known
DOM_Element prodElem = doc->createElement (tagName);
parentNode->appendChild (prodElem);
9. 在加載 xml 文件分析前,有兩種加載方式:一種直接通過文件加載,一種是通過內存加載
1. String xmlfile = “a.xml”;
Parser->parse(xmlfile.c_str());
2.MemBufInputSource 這個類處理內存的數據,然後利用 parser->parse(*men)//men 是 MemBufInputSource 的實例指針對象。
10. 在加載分析報文前,可以設置 XercesDOMParser 的一些屬性。
P arser->setValidationScheme( XercesDOMParser::Val_Auto );
Parser->setDoNamespaces( false );
Parser->setDoSchema( false );
Parser->setLoadExternalDTD( false );
// 這個部分的代碼可以參照類庫自帶的例子。
11. 我們也可以設置錯誤的處理代碼。
這部分可以查看類庫下的 DOMPrint 例子。 DOMError ,DOMErrorHandler
12. 也可以設置分析過濾的屬性
DOMNodeFilter 這個類能起到這個效果
13. 要美化文檔的格式化輸出,我們可以使用
XMLFormatter XMLFormatTarget , 用的時候可以查看。
14 我們也可以通過 DOMImplementationLs , DOMImplementation 前者是後者的基類。通過這個類我們可以創建 DOMBuilder ( parser )或 DOMWriter (序列,既可以寫到屏幕,也可以寫到文件)
如何利用Xerces C++正確處理XML文檔中的中文
作者: 張志強
下載本文示例代碼
1. 背景介紹
Apache的Xerces C++是廣大c/c++程序員非常喜歡使用的XML解析器之一。主要原因是其本身是一個開放源代碼的項目而且提供不同平臺下的庫和源代碼,故深受廣大c/c++程序員的歡迎。
Xerces C++可以到以下網站下載:
1) http://xml.apache.org/
2) http://www.vckbase.com/tools
2. 問題描述
根據軟件開發的要求,作者開發了一個文件特徵識別軟件,該軟件可根據文件特有的特徵識別出文件的類型。要求將文件特徵保存在XML文件中。根據要求作者選擇了Xerces C++作爲XML解析器。但發現出了一個嚴重的問題:被解析的XML文件中不能包含中文,否則中文將不能正確的解析。作者研究了Xerces C++提供的例子程序,發現這些例子程序解析的結果也是錯誤的。只有DOMPrint程序例外。這肯定了Xerces C++本身是支持中文的。
XML編碼:
<pdf ext="pdf" description="pdf文檔">
<magic offset="0" type="string" value="/x25/x50/x44/x46" />
</pdf>SAXPrint程序解析結果:
<pdf ext="pdf" description="pdf文檔">
<magic offset="0" type="string" value="/x25/x50/x44/x46"></magic>
</pdf>爲此,作者曾經在IBM的中文網站發現一篇文章《如何利用Xerces-C++解析包含中文字符的XML文檔》並將其所描述的辦法應用到程序中。但後來由於機器發生故障,硬盤上的數據全部丟失。不得不把以前做過的事重做一遍。因一時在IBM的網站上未找到上面提到的貼子,而且由於當時撿現成的沒有用心研究其實現方法,故不得不仔細分析Xerces C++提供的源代碼,自己動手解決中文問題。爲了今後廣大C++程序員碰到類似問題時不會像我一樣痛苦。我也決定將自己的研究結果公佈出來供大家分享。如果誰有更好的解決辦法不要忘記告訴我。
3. 原因分析
上面的例子裏,程序將“文檔”兩個中文字符解析成了亂碼。但DOMPrint程序確能夠正確解析。這表明Xerces C++對國際編碼肯定是支持的。作者通過對DOMPrint和SAXPrint兩個程序的比較跟蹤發現問題的根本就是XMLFormatter設置的問題。由於SAX是基於事件的,大多數使用者只是簡單的解析XML文檔,XMLFormatter的使用比較麻煩。而DOMPrint也是通過標準的輸出程序輸出的屏幕上的,我們不能直接使用輸出結果。
由於XML解析器解析的字符串都是XMLCh格式的,一個字符佔用一個字節,而漢字字符確要佔用兩個字節。故若不做適當的轉換,漢字的輸出結果就變成亂碼了。
4. 解決辦法
找到原因就有解決問題的方法了,明顯的需要一個把解析出來的XMLCh轉換成普通的字符串。這是解析,如果我們需要自己寫入XML文檔也有一個把普通字符串轉換爲XMLCh的過程。我把這兩個轉換過程封裝在了一個名爲“XMLStringTranslate”的類中。使用如下:
void SAXMagicHandlers::startElement(const XMLCh* const name,AttributeList& attributes)
{
XMLStringTranslate stringTranslate("gb2312");
string strName=stringTranslate.translate(name);//得到可包含漢字字符的普通字符串
string strValue="pdf文檔";
XMLCh * value= stringTranslate.translate(strValue.c_str());//將普通字符串轉換成XMLCh串
}採用XMLStringTranslate後的實際運行結果:
<pdf ext="pdf" description="pdf文檔">
<magic offset="0" type="string" value="/x25/x50/x44/x46"></magic>
</pdf>特別說明:
由於爲了防止內存釋放問題,將普通字符串轉換成XMLCh *的translate函數返回的是類的一個成員變量,故下面的代碼是不允許的:
XMLCh * value1= stringTranslate.translate("測試1");
XMLCh * value2= stringTranslate.translate("測試2");
這樣使用的結果是value1和value2的值將是一樣的(因爲其內存地址根本就是一樣的)。正確的使用方法是通過內存拷貝或則其他方法,將value1的值保存起來或則及時使用,否則value2將影響value1的值。
5. 結束語
目前,許多企業已經或者正在採用Xerces C++開發XML的應用系統,相信在應用的過程中會遇到各種問題,歡迎有興趣的朋友與我聯繫,共同交流。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/jnstone3/archive/2009/02/11/3876607.aspx