XML作為一種重要的文件格式,應用面非常之廣。從ASP.NET的web.config,到Android的頁面設計開發,Webservice通信等。有時候難免需要我們通過程序進行創建與解析,最近剛完成一個C++項目,就需要讀取XML配置文件,關於XML解析器的選擇很多,可以參考:http://www.metsky.com/archives/578.html。
個人比較喜歡Apache的開源項目,所以使用的是:Xerces。它的使用方法,其實官方上已經有很多demo,詳見:http://xerces.apache.org/xerces-c/samples-3.html。個人覺得DOMCount比較實用,下面分享一下我的個人實踐。通過DOM方式讀取XML中指定節點的屬性及文本值。
開發環境:Visual studio 2013
下載源碼就不說了,地址:http://apache.dataguru.cn//xerces/c/3/sources/xerces-c-3.1.2.zip,無法下載,可以去http://xerces.apache.org/xerces-c/download.cgi下載。
首先,編譯XercesLib工程,得到xerces-c_3_1D.dll,xerces-c_3D.lib兩個文件,其次需要在目標工程添加這2個文件,以及相應的頭文件,然后是一點配置,接下來就是編碼。
下面詳細分步進行:
1.VS 2013 打開xerces-c-3.1.2\projects\Win32\VC12\xerces-all\xerces-all.sln
選中XercesLib->右擊->編譯
2.復制xerces-c-3.1.2\Build\Win32\VC12\Debug文件夾下的xerces-c_3_1D.dll,xerces-c_3D.lib文件到目標工程的編譯輸出目錄下(有編譯過一次才有),如:~\ Debug\ 下面。
3.復制xerces-c-3.1.2下的src文件夾到目標工程下。
4.配置include Directories 增加.\src,
配置Dependencies 增加xerces-c_3D.lib,Library Directories 增加$(OutDir)(即編譯輸出目錄)
2-4步是所有調用動態庫的通用配置方法,如果明白其中的原理,其實可以靈活配置。
XML文件內容如下:
<?xml version="1.0" encoding="UTF-8"?> <config> <child> <node1> <list name="1">test11</list> <list name="2">test12</list> </node1> <node2> <list name="1">test21</list> <list name="2">test31</list> </node2> <node3> <list name="1">test31</list> <list name="2">test32</list> </node3> </child> </config>
5.開始實現編碼。
5.1包含頭文件
1 #include <xercesc/util/PlatformUtils.hpp> 2 #include <xercesc/dom/DOM.hpp> 3 #include <xercesc/sax/HandlerBase.hpp> 4 #include <xercesc/parsers/XercesDOMParser.hpp>
5.2初始化環境
1 try { 2 XMLPlatformUtils::Initialize(); 3 } 4 catch (const XMLException& toCatch) { 5 // Do your failure processing here 6 return; 7 } 8 /// 9 XercesDOMParser *parser = new XercesDOMParser(); 10 parser->setValidationScheme(XercesDOMParser::Val_Always); 11 parser->setDoNamespaces(true); // optional 12 13 ErrorHandler* errHandler = (ErrorHandler*) new HandlerBase(); 14 parser->setErrorHandler(errHandler);
5.3載入XML文件
1 try { 2 parser->parse(“D:\RUN.XML”); 3 } 4 catch (const XMLException& toCatch) { 5 char* message = XMLString::transcode(toCatch.getMessage()); 6 cout << "Exception message is: \n" 7 << message << "\n"; 8 XMLString::release(&message); 9 return; 10 } 11 catch (const DOMException& toCatch) { 12 char* message = XMLString::transcode(toCatch.msg); 13 cout << "Exception message is: \n" 14 << message << "\n"; 15 XMLString::release(&message); 16 return; 17 } 18 catch (...) { 19 cout << "Unexpected Exception \n"; 20 return; 21 }
5.4開始解析
1 DOMDocument *doc = parser->getDocument(); 2 DOMElement *root = doc->getDocumentElement();//讀取根節點
5.5 找對應節點值與屬性
1 DOMNode *DN=root; 2 DN = findchildNode(DN, "child");//查找child子節點 3 for (DN = DN->getFirstChild(); DN != 0;DN = DN->getNextSibling()) 4 {//遍歷node1,2,3子節點 5 if (DN->getNodeType() == DOMNode::ELEMENT_NODE)//這個是必要的,因為如果不判斷類型,實際上每一個節點會有一個TEXT_NODE,而且是第一個節點 6 { 7 if (XMLString::compareString(XMLString::transcode(findchildNode(DN, "list")->getAttributes()->getNamedItem(XMLString::transcode("name"))->getNodeValue()), XMLString::transcode("1")) == 0) 8 {//找到<list name=”1”>的節點 9 cout <<”對應節點值為:” << XMLString::transcode(findchildNode(DN, " list")->getTextContent())<<endl; 10 //DO IT CODE 11 … 12 13 }; 14 15 } 16 } 17 XMLPlatformUtils::Terminate();//釋放環境
下面是findchildNode函數的代碼
1 DOMNode* findchildNode(DOMNode *n, char *nodename) 2 {//尋找n節點下子節點名為nodename的節點 3 try 4 { 5 for (DOMNode *child = n->getFirstChild(); child != 0; child = child->getNextSibling()) 6 { 7 if (child->getNodeType() == DOMNode::ELEMENT_NODE && XMLString::compareString(child->getNodeName(), XMLString::transcode(nodename)) == 0) 8 { 9 return child; 10 } 11 } 12 } 13 catch (const XMLException& toCatch) 14 { 15 char* message = XMLString::transcode(toCatch.getMessage()); 16 cout << "Exception message is: \n" 17 << message << "\n"; 18 XMLString::release(&message); 19 } 20 return 0; 21 }
5.6 記得釋放環境
XMLPlatformUtils::Terminate();
1.輸出結果為
對應節點值為:test11
總結:
讀取XML有兩種模式,一種是基於事件的SAX方式,一種是DOM,本文采用DOM方式,其實與js中的getElementbyId()有些類似。代碼主體是完整的,希望不影響理解。如有需要源代碼的,可加QQ或微信:304772487或來信:thpychengai@aliyun.com