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

posted @ 2013-09-04 15:20  学海拾贝  阅读(1779)  评论(0编辑  收藏  举报