要寫一個xml解析,解析後得到到的數據變成各個類的對象.c++
解析有現成的庫,使用tinyxml,可是解析出來的類庫如何變成各個類的對象,數組
例如一下這個xml,函數
<musics> <music id="1"> <name>黑色幽默</name> <albumName>Jay</albumName> <year>2000</year> </music> <music id="2"> <name>愛在西元前</name> <albumName>范特西</albumName> <year>2001</year> </music> <music id="3"> <name>回到過去</name> <albumName>八度空間</albumName> <year>2002</year> </music> <music id="4"> <name>東風破</name> <albumName>葉惠美</albumName> <year>2003</year> </music> <music id="5"> <name>七里香</name> <albumName>七里香</albumName> <year>2004</year> </music> <music id="6"> <name>一路向北</name> <albumName>十一月的蕭邦</albumName> <year>2005</year> </music> </musics>
咱們能夠設計一個CMusics類,裏頭包含CMusic數組this
class CMusic { public: CMusic(); virtual ~CMusic(); private: string m_name; string m_albumName; int m_year; };
class CMusic class CMusics { public: CMusics(); virtual ~CMusics(); vector<CMusic*> m_musics; };
最初的想法在CMusic中定義一個函數spa
class CMusic { public: CMusic(); virtual ~CMusic(); //初版 void SetValue( string key, void* value ) { if ( key == "name" ) { this->m_name = (char*)value; } else if( key == "albumName" ) { this->m_albumName = (char*)value; } else if ( key == "year" ) { this->m_year = (int)value; } //比較糾結...若是有多個對象,那不是要比屢次... } private: string m_name; string m_albumName; int m_year; };
改進版本設計
class CMusic { public: CMusic() { m_mapfunc["id"] = &CMusic::SetName; m_mapfunc["albumName"] = &CMusic::SetAlbumName; m_mapfunc["year"] = &CMusic::SetYear; } virtual ~CMusic(); //改進版 typedef void ( CMusic::*Func )( string key, string strAttribute, void* value ); typedef map<string, Func>MusicMap; void SetName( string key, string strAttribute, void* value ) { this->m_name = (char*)value; } void SetAlbumName( string key, string strAttribute, void* value ) { this->m_albumName = (char*)value; } void SetYear( string key, string strAttribute, void* value ) { this->m_year = *(int*)value; } MusicMap m_mapfunc; private: string m_name; string m_albumName; int m_year; };
接着咱們要定義一個處理xml的類IXmlAtom指針
class IXmlAtom { public: /** 處理xml結點 */ virtual void DealXmlNode( string strNode, string strNodeAttribute, string Value) = 0; //建立字節點指針 virtual IXmlAtom* CreateItem( string key ){ return NULL; } virtual void LoadXml(char* xmlPath); virtual void ParseXml(char* strXmlStream); private: string DumpNode(TiXmlNode * pParent,TiXmlNode * pNode,IXmlAtom* pIAtom, int flag); };
把須要生成xml對象的類繼承該類.code
DealXmlNode的做用是用來各個子類調用上面的回調函數xml
CreateItem的做用是當xml中嵌套多層xml的時候.根據名字建立類(若是隻有一層xml數據則不須要重載這個函數)對象
其中DumpNode實現的代碼以下:
string IXmlAtom::DumpNode(TiXmlNode * pParent,TiXmlNode * pNode,IXmlAtom* pIAtom, int flag) { if(pNode == NULL) { return ""; } TiXmlText * pText = NULL; TiXmlNode * pChildNode = NULL; int t = pNode->Type(); if( t == TiXmlText::TINYXML_TEXT ) //節點類型是text節點 { const char* pParentValue = pParent->Value(); pText = pNode->ToText(); string text = pText->Value(); pIAtom->DealXmlNode(pParentValue,"",text.c_str()); } else if( t == TiXmlText::TINYXML_ELEMENT ) //節點類型是Element { int num = flag; const char* pNodeValue = pNode->Value(); //輸出屬性 TiXmlElement * pElement = pNode->ToElement(); TiXmlAttribute * pAttr = pElement->FirstAttribute(); if(pAttr != NULL) { string tmpAttrVal = ""; string tmpAttrName = ""; do { tmpAttrVal = pAttr->Value(); tmpAttrName = pAttr->Name(); pIAtom->DealXmlNode(pNodeValue,tmpAttrName,tmpAttrVal ); }while(pAttr = pAttr->Next()); } } //循環訪問它的每個元素 TiXmlNode * pTempParent = pNode; for(pChildNode=pNode->FirstChild();pChildNode!=0;pChildNode = pChildNode->NextSibling()) { const char* data=pChildNode->Value(); IXmlAtom* pXmlAtom = pIAtom->CreateItem(pChildNode->Value()); DumpNode(pTempParent,pChildNode, pXmlAtom == NULL? pIAtom : pXmlAtom,flag+1); } return ""; }
調用
int main(int argc, char* argv[]) { //printf("Hello World!\n"); CMusics music; music.LoadXml("C:\\1.xml"); return 0; }
demo下載地址:
xml中包含多個對象的時候.寫回調函數就每次都須要定義,能夠使用c++函數模板來處理