因為項目需要讀取xml配置文件,在原來調查一番后,項目組使用了tinyxml.
tinyxml確實簡單,非常清楚的就把讀取方案寫出來了。但是,由於后期xml文件越來越大(2.5M,大概1w多行數據),結果導致運行速度越來越低(17s)。
於是,不得不開始尋找改善方案。
在網上調查一番后,普遍認為xml讀取有以下的幾種方式:
RapidXml、pugixml 0.3、pugxml、TinyXml
並且清楚的給出了各個之間的性能對比。
|
|
|
strlen() | RapidXml | pugixml 0.3 | pugxml | TinyXml |
|---|---|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
抱着試一試的態度,我采用了rapidxml來進行改善,結果運行速度減少到了1.6S!
下面是rapidxml的一些使用注意事項,總結一下,幫助大家少走彎路。
1.大家網上百度的時候,肯定都會存在這樣的代碼:
1 file<> fdoc("config.xml"); 2 std::cout<<fdoc.data()<<std::endl; 3 xml_document<> doc; 4 doc.parse<parse_full>(fdoc.data());
代碼本身是沒有錯的,但是導入工程后,就會在file<> fdoc拋出異常。
調查許久后發現:file<> fdoc后面必須是絕對路徑,所以我們讀取的時候不必要像上面那么書寫,可以這樣:
1 using namespace rapidxml; 2 std::string strXml = m_strXmlPath; // m_strXmlPath是獲取xml路徑的方法,可以自己去實現 3 strXml.append("\\CA_Basic.xml"); 4 file<> fdoc(strXml.c_str()); 5 xml_document<> doc; 6 doc.parse<0>(fdoc.data());
2.網上的xml的格式都是很整齊的,比如:
1 <config> 2 <color> 3 <red>0.1</red> 4 <green>0.1</green> 5 <blue>0.1</blue> 6 <alpha>1.0</alpha> 7 </color> 8 <size> 9 <x>640</x> 10 <y>480</y> 11 <w>0</w> 12 <h>0</h> 13 </size> 14 <mode fullscreen="false">screen mode</mode> 15 </config>
這樣讀取起來確實和簡單,按照一下的方案就行了。
1 //! 獲取根節點 2 xml_node<>* root = doc.first_node(); 3 4 //! 獲取根節點第一個節點 5 xml_node<>* node1 = root->first_node(); 6 xml_node<>* node11 = node1->first_node(); 7 ......
可是實際運用的時候不會這么簡單的,比如我們有以下的xml:
1 <ca_table> 2 <ce_port no="0"> 3 <ca item_id ="10004000" curr_ec="1" next_ec="2"> 4 <firm no ="0" vv ="10" ll ="40" pp ="0000"> </firm> 5 <firm no ="1" vv ="11" ll ="40" pp ="0000"> </firm> 6 <board_hard pn ="CA07111-C631" sn ="PP09280285" rev ="40" other =""> </board_hard> 7 <port port_no ="0" item_id ="11004000" rate ="0" node_name="500000E0D1000100" wwn="500000E0D1000100" MacAddress="B0ACFAA3A000" lu_reset_scope="01" reserveCancel="00"> 8 </port> 9 </ca> 10 </ce_port> 11 </ca_table>
這個時候就比較麻煩了,我們可以這樣去讀取:
1 using namespace rapidxml; 2 std::string strXml = m_strXmlPath; 3 strXml.append("\\CA_Basic.xml"); 4 file<> fdoc(strXml.c_str()); 5 xml_document<> doc; 6 doc.parse<0>(fdoc.data()); 7 8 xml_node<>* root = doc.first_node(); // 獲取根節點<ca_table> 9 xml_node<>* pCePortNodeBasic = root->first_node("ce_port"); // 獲取節點<ce_port> 10 if (!pCePortNodeBasic) { 11 return; 12 } 13 xml_node<>* pCaBasic = pCePortNodeBasic->first_node("ca"); // 獲取節點<ca> 14 xml_attribute<>* p = pCaBasic ->first_attribute(“item_id”); // 獲取節點<ca>中的itemid 15 unsigned long long value = strtol(p->value(), NULL, 16); // p->value()獲取的是字符,需要將其轉換為數值類型
3.並列的xml怎么處理?
跟tinyxml一樣,rapidxml也自己封裝了搜尋下一個並列的xml的函數next_sibling(),直接調用即可。
4.命名空間rapidxml
在使用rapidxml的時候,盡可能的在調用rapidxml的地方再使用rapidxml命名空間,最好不要放到全局,以免引起混淆和帶來性能問題
