(原)C++解析XML生成類對象_v1.0 函數指針

要寫一個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下載地址:

ParseXml_V1.rar

 

xml中包含多個對象的時候.寫回調函數就每次都須要定義,能夠使用c++函數模板來處理

相關文章
相關標籤/搜索