BOOST之property_tree 及解析XML詳解
摘要:
property_tree是一個儲存了多個屬性值的屬性資料結構,可以用類似路徑的簡單方式訪問任意節點的屬性,而且每個節點都可以用類似STL的風格遍歷子節點。property_tree特別適合於應用程式的配置資料處理,可以解析xml、ini、json和info四個格式的文字資料。
在處理四種格式的檔案時,除包含標頭檔案、讀檔案、寫檔案時有部分區別外,其他對檔案內部資料操作時基本一致(因為檔案格式都基本一直)。實際上,property_tree內部使用的就是一個小巧快速的開源XML解析器——rapidxml。
使用方法:
1)不同:(XXX分別程式碼xml、json、ini、info)
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/XXX_parser.hpp> using namespace boost::property_tree; void main(void) { ptree pt; read_XXX("./test.XXX", pt); // 讀檔案 // ....其他操作 write_XXX(cout, pt); // 寫檔案,有兩種格式: // void write_XXX(const string &, Ptree &pt); // void write_XXX(basic_ostream &, Ptree &pt); }
2)相同:(下面以xml為基礎詳細介紹,其他三種類型沒測試過,囧~)
測試的XML檔案:test.xml
測試程式碼:<config> <file title="windows" size="10Mb"> <!-- File Fisrt Comment --> <!-- File Second Comment --> <paths attr="directory"> <!-- Paths Comment --> <pathname title="123">abc</pathname> <pathname title="456">efg</pathname> <pathname title="789">hij</pathname> </paths> <paths> <pathname title="111">klm</pathname> <pathname title="222">nop</pathname> <pathname title="333">qrs</pathname> </paths> </file> </config>
#include <iostream> #include <string> #include <boost/typeof/typeof.hpp> #include <boost/property_tree/ptree.hpp> #include <boost/property_tree/xml_parser.hpp> using namespace std; using namespace boost::property_tree; int main(void) { char szXmlFile[] = "E:/test.xml"; string strTmp; ptree pt; xml_parser::read_xml(szXmlFile, pt); BOOST_AUTO(child, pt.get_child("config.file")); for (BOOST_AUTO(pos, child.begin()); pos != child.end(); ++pos) { strTmp.clear(); if ("<xmlattr>" == pos->first) { strTmp = pos->second.get<string>("title"); // 輸出:windows cout<<strTmp<<"\t"; strTmp = pos->second.get<string>("size"); // 輸出:10Mb cout<<strTmp<<"\t"; strTmp = pos->second.get<string>("noexits", "This is default"); cout<<strTmp<<endl; // 輸出:This is default } else if ("<xmlcomment>" == pos->first) { strTmp = pos->second.data(); // 第一次輸出:File First Comment cout<<strTmp<<endl; // 第二次輸出:File Second Comment } else { BOOST_AUTO(nextchild, pos->second.get_child("")); for (BOOST_AUTO(nextpos, nextchild.begin()); nextpos != nextchild.end(); ++nextpos) { strTmp.clear(); if ("<xmlattr>" == nextpos->first) { strTmp = nextpos->second.get<string>("attr"); // 輸出:directory cout<<strTmp<<endl; } else if ("<xmlcomment>" == nextpos->first) { strTmp = nextpos->second.data(); // 輸出:Paths Comment cout<<strTmp<<endl; } else { strTmp = nextpos->second.get<string>("<xmlattr>.title"); cout<<strTmp<<"\t"; strTmp = nextpos->second.data(); cout<<strTmp<<endl; } } } } return 0; }
測試結果:
分析:從上述測試中可以看出,BOOST封裝的RapidXml開源庫,是將XML檔案內容解析為一個樹狀結構。比如說本例中使用的節點“config.file”,具有五個子節點:一個屬性子節點、兩個註釋子節點、兩個資料子節點,且順序為屬性→註釋→資料。
①屬性子節點:
每個節點只有一個屬性子節點,是一對多關係,即一個屬性子節點對應多個屬性!
"if ("<xmlattr>" == pos->first)",然後獲取屬性的值則為“pos->second.get<string>("title")”和“pos->second.get<string>("size")”。注意這裡獲取屬性,不再是"<xmlattr>.title",因為此時pos已經指向本節點,不再需要用"<xmlattr>"遞推到屬性子節點!
②註釋子節點:節點可以有多個屬性子節點,是一對一關係!!!
”if ("<xmlcomment>" == pos->first)“,獲取屬性則“pos->second.data()”;
③資料子節點:這種節點又可以重新看做是一個節點,下面會對應屬性子節點、註釋子節點、資料子節點。但注意“pos->second.get_child("")”是返回當前節點的所有子節點(包含屬性、註釋、資料),而“pt.get_child("config.file")“是返回file節點下所有節點(包含屬性、註釋、資料)。