RAPIDXML 中文手冊,根據官方文檔完整翻譯!


簡介:
這個號稱是最快的DOM模型XML分析器,在使用它之前我都是用TinyXML的,因為它小巧和容易上手,但真正在項目中使用時才發現如果分析一個比較大的XML時TinyXML還是表現一般,所以我們決定使用RapidXML作為替換。當然是為了獲取更好的性能,經過我們的初步試驗后發現確實比TinyXML好,但看到網上關於rapidxml的資料零散,而且也缺乏一份較為權威的說明文檔,找來找去還是得看官方的英文手冊。所以我又下單了,翻譯官方提供的手冊,希望給各位朋友提供一些綿薄之力。



1. RapidXml 是什么?
RapidXML是一個試圖創建最快的XML DOM分析器,當然同時也保留它的可用性、移植性和適當的W3C兼容性。它是一個用C++編寫的即用分析器,在相同的數據上它的分析速度接近於strlen()函數。
整個分析器就包含在單獨的一個頭文件中,所以不需要任何的構建和鏈接。當你使用的時候只需將 rapidxml.hpp 文件復制到一個合適的地方(例如你的工程目錄下),然后在任何需要它的地方包含一下即可。或許你也會用到 rapidxml_print.hpp 頭文件里的打印函數。

1.1 Dependencies And Compatibility(依賴和兼容)
RadpidXML除了使用到標准C++庫(<cassert>, <cstdlib>, <new> 和 <exception>, 除非異常被關閉了)的很小一個子集外沒有關聯其它東西了。它能被任何標准編譯器所編譯,並已在Visual C++ 2003, Visual C++ 2005, Visual C++ 2008, gcc 3, gcc 4, 和 Comeau 4.3.3. 中測試通過。也就是說在這些編譯器上沒出現任何的警告信息,即使在最高警告級別上。
1.2 Character Types And Encodings(字符類型和編碼)
RadpidXML並不知道字符集的類型(譯注:因為它是基於模板,可以自定義字符類型),所以在窄字符和寬字符下都能工作。當前版本並不完全支持UTF-16和UTF-32,所以使用寬字符稍微有點不適合。不管怎樣,如果數據的字節順序與當前系統匹配,它能成功分析包含UTF-16或UTF-32 的wchar_t 字符串。UTF-8是完全支持的,包括所有的數值字符引用,這些字符會被擴展到適當的UTF-8字節順序(除非你打開parse_no_utf8 flag 標記)。
要注意RapidXml不會對 name() 和 value() 函數返回的字符串進行解碼,因為函數會根據源代碼文件本身的編碼模式來編碼(譯注:也就是說如果你的源代碼文件編碼格式為ANSI,則name()函數返回的字符串編碼也是ANSI,如果源代碼文件的編碼格式為UTF-8,字符串編碼也是UTF-8)。Rapidxml能解釋和擴展下列的字符應用:' & " < > &#...;其它字符引用不會被展開。

1.3 Error Handling (錯誤處理)
默認情況下,RapidXml使用C++異常來報告錯誤,如果你不喜歡這個行為,可以使用RAPIDXML_NO_EXCEPTIONS定義來制止異常代碼,請參考 parse_error 類和 parse_error_handler() (http://rapidxml.sourceforge.net/manual.html#namespacerapidxml_ff5d67f74437199d316d2b2660653ae1_1ff5d67f74437199d316d2b2660653ae1) 函數。
1.4 Memory Allocation(內存分配)
RadpidXml使用一個特別的內存池對象來分配所有的節點和屬性,因為直接使用 new 操作符來分配太慢了,池中的內存分配可用 memory_pool::set_allocator() (http://rapidxml.sourceforge.net/manual.html#classrapidxml_1_1memory__pool_c0a55a6ef0837dca67572e357100d78a_1c0a55a6ef0837dca67572e357100d78a) 函數來自定義,詳細信息請看 memory_pool (http://rapidxml.sourceforge.net/manual.html#classrapidxml_1_1memory__pool) 類。
1.5 W3C Compliance(W3C兼容)
RapidXml並不是一個與W3C完全一致的分析器,主要原因是忽略了 DOCTYPE 聲明。還有一些其它原因,如兼容性不是很好,但是,它能成功分析和生成與W3C文件組(有關XML處理器的規格設計超過1000個文件)定義的完整XML樹。即使在不良的情況下它也能對空白符進行正常化處理和對一部分字符集實體進行替換。
1.6 API Design(API設計)
為了盡可能的減少代碼量,RadpidXML API已經很簡約了,並且為了能在它嵌入的環境中更容易使用,一些附加的功能被分割在不同的頭文件中:rapidxml_utils.hpp 和rapidxml_print.hpp (http://rapidxml.sourceforge.net/manual.html#rapidxml__print_8hpp)。這兩個頭文件並不是必須的,並且當前也沒有相關文檔(但是代碼中有注釋)。
1.7 Reliability(可靠性)
RadpidXML很健壯,因為它通過了一大堆的單元測試。已經特別小心地確保分析器的穩定性,不管你扔什么文本給它。其中的一項單元測試用了隨機產生100,000個XML文檔錯誤,RapidXml也能創建它(還未更正)。當這些錯誤被引入后RapidXml還是能通過這項測試,並且不會被破壞和進入死循環。
其它的單元測試也和RapidXMl進行肉搏,穩定的XML分析器,和其它為了符合一大推文檔和功能的測試。
另外RapidXml進行了1000多個W3C兼容性文件測試,並且都能取得正確的結果。其它的測試包括對API函數的測試,並且測試各種各樣的分析模式。


1.8 Acknowledgements(致謝)
I would like to thank Arseny Kapoulkine for his work on pugixml (http://code.google.com/p/pugixml), which was an inspiration for this project. Additional thanks go to Kristen Wegner for creating pugxml (http://www.codeproject.com/soap/pugxml.asp), from which pugixml was derived. Janusz Wohlfeil kindly ran RapidXml speed tests on hardware that I did not have access to, allowing me to expand performance comparison table.

2. Two Minute Tutorial(兩分鍾教程)
2.1 Parsing(分析)
下面的代碼示范了RapidXml分析一個以0結尾的字符串text:
using namespace rapidxml;
xml_document<> doc; // 字符類型默認為char
doc.parse<0>(text); // 0表示默認分析標記
doc對象現在是一個DOM樹,代表已分析的XML。因為所有的RadpidXml接口都包含在命名空間 rapidxml中,用戶要么加入此命令空間,要么使用完整的命名(譯注:即要使用doc必須使用 rapidxml::xml_docment<> doc),類xml_document代表一個DOM層次的根節點。除了是公共的繼承點,它還是一個xml_node 和memory_pool。xml_document::parse()函數的模板參數是用來指定分析標記的,它可以用來對分析器進行微調。但要注意,標記必須是一個編譯器的常數。
2.2 Accessing The DOM Tree(訪問DOM樹)
要訪問DOM樹,使用xml_node和xml_attribute類中的方法即可:
cout << "Name of my first node is: " << doc.first_node()->name() << "\n";
xml_node<> *node = doc.first_node("foobar");
cout << "Node foobar has value " << node->value() << "\n";
for (xml_attribute<> *attr = node->first_attribute();
attr; attr = attr->next_attribute())
{
cout << "Node foobar has attribute " << attr->name() << " ";
cout << "with value " << attr->value() << "\n";
}
2.3 Modifying The DOM Tree(修改DOM樹)
分析器生成的DOM樹完全可以修改。可以增加和刪除節點和屬性,還有他們的內容。下面的例子創建了一個HTML文檔,並有個單獨的鏈接到google.com網站:
xml_document<> doc;
xml_node<> *node = doc.allocate_node(node_element, "a", "Google");
doc.append_node(node);
xml_attribute<> *attr = doc.allocate_attribute("href", "google.com");
node->append_attribute(attr);


其中一個特點是節點和屬性都不擁有它們的名稱和值。這是因為通常它們都只保存指向源文本的指針。所以,當關聯一個新的名稱或值給節點時,要特別小心字符串的生命周期。最簡單的方法是通過xml_document內存池來分配字符串。在上面的例子中其實是不需要的,因為我們只關聯了字符常量。但是下面的例子就使用memory_pool::allocate_string() (http://rapidxml.sourceforge.net/manual.html#classrapidxml_1_1memory__pool_69729185bc59b0875192d667c47b8859_169729185bc59b0875192d667c47b8859)函數來分配節點名稱(擁有與文檔一樣的生命周期),並將它關聯到一個新的節點:
xml_document<> doc;
char *node_name = doc.allocate_string(name); // 分配字符串並將名稱復制進去
xml_node<> *node = doc.allocate_node(node_element, node_name); // 為 node_name設置節點名稱
查看 參考 小節可看到這個接口的描述。
2.4 Printing XML(打印XML)
你可以將xml_document和xml_node對象輸出為一個XML字符串。使用print()函數或操作符 operator<<,在 rapidxml_print.hpp (http://rapidxml.sourceforge.net/manual.html#rapidxml__print_8hpp) 頭文件中可找到這些定義。
using namespace rapidxml;
xml_document<> doc; // 字符類型默認為 char
// ... 一些填充文檔的代碼
// 使用標准字符流operator <<
std::cout << doc; 

// 用print函數來輸出流,指定了打印參數
print(std::cout, doc, 0); // 0 表示默認

// 通過輸出迭代器來打印字符串
std::string s;
print(std::back_inserter(s), doc, 0);

// 通過輸出迭代器來輸出到內存緩存里
char buffer[4096]; // 你必須保證緩存足夠大!
char *end = print(buffer, doc, 0); // end包含了指向最后一個字符的指針
*end = 0; // 在XML后面添加字符終止符
3. Differences From Regular XML Parsers(與常規XML分析器的不同之處)
RapidXml是一個原位分析器,能提供非常快的分析速度。原位的意思是分析器並不做字符串的拷貝,而是在DOM層次中放置指向源文本的指針。
3.1 Lifetime Of Source Text(源文本的生命周期)
原位分析需要源文本的生命周期與XML文檔對象一樣長。如果源文本銷毀了,DOM樹里的節點名稱和值也會跟着銷毀,而且,空白符處理,字符集轉換,和0結尾的字符串都需要在分析期間被修改(但不是破壞性的)。這就使得Rapidxml進行下一步分析時字符串不再有效了。
但是在大多數情況下,這些都不是嚴重的問題。
3.2 Ownership Of Strings(字符串的所有權)
Rapidxml生成的節點和屬性都不擁有它們自己的名稱和值字符串。它們只是保留了指向名稱和值的指針。也就是說,當你用xml_base::name(const Ch *) (http://rapidxml.sourceforge.net/manual.html#classrapidxml_1_1xml__base_e099c291e104a0d277307fe71f5e0f9e_1e099c291e104a0d277307fe71f5e0f9e) 或 xml_base::value(const Ch *) (http://rapidxml.sourceforge.net/manual.html#classrapidxml_1_1xml__base_18c7469acdca771de9b4f3054053029c_118c7469acdca771de9b4f3054053029c) 函數時必須非常小心的設置這些值。要小心保證傳遞進來的字符串擁有與節點和屬性一樣長的生命周期。也可以簡單地通過使用文檔的內存池來分配這些字符串。使用memory_pool::allocate_string() (http://rapidxml.sourceforge.net/manual.html#classrapidxml_1_1memory__pool_69729185bc59b0875192d667c47b8859_169729185bc59b0875192d667c47b8859)函數可達到此目的。
3.3 Destructive Vs Non-Destructive Mode(破壞模式和非破壞模式) 
默認情況下,當分析器進行分析處理時會修改源文本。這時因為需要做字符集的轉換、空白符常規化、字符串0終止。
可能在某些情況下這個行為不好,例如源文本在一個只讀的內存中,或者是從文件中直接映射過來的。通過使用適當的分析標記(parse_non_destructive),源文本修改模式可以被關閉。但是,因為Rapidxml做了原位分析,該標記明顯有下列的副作用:
· 不作空白符的正常化處理
· 不作實體引用轉換
· 名稱和值都是非0終止的,你必須使用xml_base::name_size() (http://rapidxml.sourceforge.net/manual.html#classrapidxml_1_1xml__base_0dae694c8f7e4d89f1003e2f3a15a43c_10dae694c8f7e4d89f1003e2f3a15a43c) 和 xml_base::value_size() (http://rapidxml.sourceforge.net/manual.html#classrapidxml_1_1xml__base_aed5ae791b7164c1ee5e649198cbb3db_1aed5ae791b7164c1ee5e649198cbb3db)函數來告訴他們結束。


免責聲明!

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



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