(原)C++解析XML生成类对象_v1.0 函数指针

要写一个xml解析,解析后获得到的数据变成各个类的对象.

解析有现成的库,使用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数组

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中定义一个函数

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对象的类继承该类.

DealXmlNode的作用是用来各个子类调用上面的回调函数

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++函数模板来处理

你可能感兴趣的:(解析xml)