1. 程式人生 > >BOOST之property_tree 及解析XML詳解

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節點下所有節點(包含屬性、註釋、資料)。