[xml解析]rapidxml讀取文件


因為項目需要讀取xml配置文件,在原來調查一番后,項目組使用了tinyxml.

tinyxml確實簡單,非常清楚的就把讀取方案寫出來了。但是,由於后期xml文件越來越大(2.5M,大概1w多行數據),結果導致運行速度越來越低(17s)。

於是,不得不開始尋找改善方案。

在網上調查一番后,普遍認為xml讀取有以下的幾種方式:

RapidXml、pugixml 0.3pugxmlTinyXml

並且清楚的給出了各個之間的性能對比。

Platform
Compiler
strlen() RapidXml pugixml 0.3 pugxml TinyXml
Pentium 4
MSVC 8.0
2.5
5.4
7.0
61.7
298.8
Pentium 4
gcc 4.1.1
0.8
6.1
9.5
67.0
413.2
Core 2
MSVC 8.0
1.0
4.5
5.0
24.6
154.8
Core 2
gcc 4.1.1
0.6
4.6
5.4
28.3
229.3
Athlon XP
MSVC 8.0
3.1
7.7
8.0
25.5
182.6
Athlon XP
gcc 4.1.1
0.9
8.2
9.2
33.7
265.2
Pentium 3
MSVC 8.0
2.0
6.3
7.0
30.9
211.9
Pentium 3
gcc 4.1.1
1.0
6.7
8.9
35.3
316.0

抱着試一試的態度,我采用了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命名空間,最好不要放到全局,以免引起混淆和帶來性能問題


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM