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

时间:2024-01-10 14:06:08

要写一个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) = ; //创建字节点指针
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!=;pChildNode = pChildNode->NextSibling())
{
const char* data=pChildNode->Value();
IXmlAtom* pXmlAtom = pIAtom->CreateItem(pChildNode->Value());
DumpNode(pTempParent,pChildNode, pXmlAtom == NULL? pIAtom : pXmlAtom,flag+); }
return "";
}

调用

int main(int argc, char* argv[])
{
//printf("Hello World!\n");
CMusics music;
music.LoadXml("C:\\1.xml");
return ;
}

demo下载地址:

ParseXml_V1.rar

xml中包含多个对象的时候.写回调函数就每次都需要定义,可以使用c++函数模板来处理