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

解析有现成的库,使用tinyxml,但是解析出来的类库如何变成各个类的对象,

例如一下这个xml,

  1. <musics>
  2.  
  3. <music id="1">
  4. <name>黑色幽默</name>
  5. <albumName>Jay</albumName>
  6. <year>2000</year>
  7. </music>
  8.  
  9. <music id="2">
  10. <name>爱在西元前</name>
  11. <albumName>范特西</albumName>
  12. <year>2001</year>
  13. </music>
  14.  
  15. <music id="3">
  16. <name>回到过去</name>
  17. <albumName>八度空间</albumName>
  18. <year>2002</year>
  19. </music>
  20.  
  21. <music id="4">
  22. <name>东风破</name>
  23. <albumName>叶惠美</albumName>
  24. <year>2003</year>
  25. </music>
  26.  
  27. <music id="5">
  28. <name>七里香</name>
  29. <albumName>七里香</albumName>
  30. <year>2004</year>
  31. </music>
  32.  
  33. <music id="6">
  34. <name>一路向北</name>
  35. <albumName>十一月的萧邦</albumName>
  36. <year>2005</year>
  37. </music>
  38. </musics>

我们可以设计一个CMusics类,里头包含CMusic数组

  1. class CMusic
  2. {
  3. public:
  4. CMusic();
  5. virtual ~CMusic();
  6.  
  7. private:
  8. string m_name;
  9. string m_albumName;
  10. int m_year;
  11. };
  1. class CMusic
  2. class CMusics
  3. {
  4. public:
  5. CMusics();
  6. virtual ~CMusics();
  7. vector<CMusic*> m_musics;
  8.  
  9. };

最初的想法在CMusic中定义一个函数

  1. class CMusic
  2. {
  3. public:
  4. CMusic();
  5. virtual ~CMusic();
  6. //第一版
  7. void SetValue( string key, void* value )
  8. {
  9. if ( key == "name" )
  10. {
  11. this->m_name = (char*)value;
  12. }
  13. else if( key == "albumName" )
  14. {
  15. this->m_albumName = (char*)value;
  16. }
  17. else if ( key == "year" )
  18. {
  19. this->m_year = (int)value;
  20. }
  21. //比较纠结...如果有多个对象,那不是要比多次...
  22. }
  23.  
  24. private:
  25. string m_name;
  26. string m_albumName;
  27. int m_year;
  28. };

改进版本

  1. class CMusic
  2. {
  3. public:
  4. CMusic()
  5. {
  6. m_mapfunc["id"] = &CMusic::SetName;
  7. m_mapfunc["albumName"] = &CMusic::SetAlbumName;
  8. m_mapfunc["year"] = &CMusic::SetYear;
  9. }
  10. virtual ~CMusic();
  11.  
  12. //改进版
  13. typedef void ( CMusic::*Func )( string key, string strAttribute, void* value );
  14. typedef map<string, Func>MusicMap;
  15.  
  16. void SetName( string key, string strAttribute, void* value )
  17. {
  18. this->m_name = (char*)value;
  19. }
  20.  
  21. void SetAlbumName( string key, string strAttribute, void* value )
  22. {
  23. this->m_albumName = (char*)value;
  24. }
  25.  
  26. void SetYear( string key, string strAttribute, void* value )
  27. {
  28. this->m_year = *(int*)value;
  29. }
  30.  
  31. MusicMap m_mapfunc;
  32.  
  33. private:
  34. string m_name;
  35. string m_albumName;
  36. int m_year;
  37. };

接着我们要定义一个处理xml的类IXmlAtom

  1. class IXmlAtom
  2. {
  3. public:
  4. /** 处理xml结点 */
  5. virtual void DealXmlNode( string strNode, string strNodeAttribute, string Value) = ;
  6.  
  7. //创建字节点指针
  8. virtual IXmlAtom* CreateItem( string key ){ return NULL; }
  9.  
  10. virtual void LoadXml(char* xmlPath);
  11.  
  12. virtual void ParseXml(char* strXmlStream);
  13.  
  14. private:
  15. string DumpNode(TiXmlNode * pParent,TiXmlNode * pNode,IXmlAtom* pIAtom, int flag);
  16. };

把需要生成xml对象的类继承该类.

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

CreateItem的作用是当xml中嵌套多层xml的时候.根据名字创建类(如果只有一层xml数据则不需要重载这个函数)

其中DumpNode实现的代码如下:

  1. string IXmlAtom::DumpNode(TiXmlNode * pParent,TiXmlNode * pNode,IXmlAtom* pIAtom, int flag)
  2. {
  3. if(pNode == NULL)
  4. {
  5. return "";
  6. }
  7. TiXmlText * pText = NULL;
  8. TiXmlNode * pChildNode = NULL;
  9. int t = pNode->Type();
  10. if( t == TiXmlText::TINYXML_TEXT ) //节点类型是text节点
  11. {
  12. const char* pParentValue = pParent->Value();
  13. pText = pNode->ToText();
  14. string text = pText->Value();
  15. pIAtom->DealXmlNode(pParentValue,"",text.c_str());
  16. }
  17. else if( t == TiXmlText::TINYXML_ELEMENT ) //节点类型是Element
  18. {
  19. int num = flag;
  20.  
  21. const char* pNodeValue = pNode->Value();
  22.  
  23. //输出属性
  24. TiXmlElement * pElement = pNode->ToElement();
  25. TiXmlAttribute * pAttr = pElement->FirstAttribute();
  26. if(pAttr != NULL)
  27. {
  28. string tmpAttrVal = "";
  29. string tmpAttrName = "";
  30. do
  31. {
  32. tmpAttrVal = pAttr->Value();
  33. tmpAttrName = pAttr->Name();
  34. pIAtom->DealXmlNode(pNodeValue,tmpAttrName,tmpAttrVal );
  35. }while(pAttr = pAttr->Next());
  36. }
  37. }
  38. //循环访问它的每一个元素
  39. TiXmlNode * pTempParent = pNode;
  40. for(pChildNode=pNode->FirstChild();pChildNode!=;pChildNode = pChildNode->NextSibling())
  41. {
  42. const char* data=pChildNode->Value();
  43. IXmlAtom* pXmlAtom = pIAtom->CreateItem(pChildNode->Value());
  44. DumpNode(pTempParent,pChildNode, pXmlAtom == NULL? pIAtom : pXmlAtom,flag+);
  45.  
  46. }
  47. return "";
  48. }

调用

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

demo下载地址:

ParseXml_V1.rar

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

(原)C++解析XML生成类对象_v1.0 函数指针的更多相关文章

  1. 动态加载Dll时,通过Type生成类对象

    原文:动态加载Dll时,通过Type生成类对象 转:http://www.cnblogs.com/zfanlong1314/p/4197383.html "反射"其实就是利用程序集 ...

  2. 基类中定义的虚函数在派生类中重新定义时,其函数原型,包括返回类型、函数名、参数个数、参数类型及参数的先后顺序,都必须与基类中的原型完全相同 but------> 可以返回派生类对象的引用或指针

      您查询的关键词是:c++primer习题15.25 以下是该网页在北京时间 2016年07月15日 02:57:08 的快照: 如果打开速度慢,可以尝试快速版:如果想更新或删除快照,可以投诉快照. ...

  3. 由剑指offer引发的思考——对象中虚函数指针的大小

    先看一个简单的问题: 一.定义一个空的类型,对于其对象我们sizeof其大小,是1字节.因为我们定义一个类型,编译器必须为其分配空间,具体分配多少是编译器决定,vs是1字节,分配在栈区. 那,这一个字 ...

  4. Dom4J 解析xml ,类查询

    /** * 从XML文件比对,传入provinceId 返回 provinceShortName * @param provinceid * @return */ public static Stri ...

  5. jaxb解析xml工具类

    [quote]jaxb jdk 自带的解析xml的一种方式支持,只需要用注解对javabean进行数据绑定[/quote] package com.nnk.flowrecharge.common;im ...

  6. 使用dom4j解析xml为json对象

    import java.util.List; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j. ...

  7. java定义类 对象,引用,指针

    java是根据面向对象编程,因此有类和对象的概念,类分为普通类与抽象类. 一.定义类 类由N个 构造器  成员变量  方法组成,可以不定义,也可以根据语法定义N个. [修饰符] class 类名{ 构 ...

  8. error LNK2019 无法解析的外部符号------类模板和内敛函数

    今天用类模型实现一个单链表,开始是.h和.cpp将类模板的声明与实现分开写的,结果总是报错: 错误 error LNK2019: 无法解析的外部符号 ?$SingleList@H@@QAE@XZ),该 ...

  9. c++特性:指向类成员的指针和非类型类模板参数和函数指针返回值 参数推导机制和关联型别

    一.c++允许定义指向类成员的指针,包括类函数成员指针和类数据成员指针 格式如下: class A { public: void func(){printf("This is a funct ...

随机推荐

  1. Java [leetcode 35]Search Insert Position

    题目描述: Given a sorted array and a target value, return the index if the target is found. If not, retu ...

  2. 【原创】batch-GD, SGD, Mini-batch-GD, Stochastic GD, Online-GD -- 大数据背景下的梯度训练算法

    机器学习中梯度下降(Gradient Descent, GD)算法只需要计算损失函数的一阶导数,计算代价小,非常适合训练数据非常大的应用. 梯度下降法的物理意义很好理解,就是沿着当前点的梯度方向进行线 ...

  3. 【转】Cocos2d-x 程序是如何开始运行与结束的

    转自:http://blog.leafsoar.com/archives/2013/05-05.html 题记:对于技术,我们大可不必挖得那么深,但一定要具备可以挖得很深的能力 问题的由来 怎么样使用 ...

  4. 如何卸载eclipse中的ADT

    卸载ADT的方法,方法如下: 1.选择 Help > Install New Software: 2.在"Details" 面板中, 点击"What is alre ...

  5. Collection Of SVM Libraries By Language via datasciencecentral

    http://www.datasciencecentral.com/profiles/blogs/collection-of-svm-libraries-by-language Support vec ...

  6. HDU 4081 Qin Shi Huang's National Road System 最小生成树

    分析:http://www.cnblogs.com/wally/archive/2013/02/04/2892194.html 这个题就是多一个限制,就是求包含每条边的最小生成树,这个求出原始最小生成 ...

  7. C#操作Json(转)

    原文:http://wenku.baidu.com/link?url=3dlqKdF26ZdQIAcX9jvP2ZYEtl3J0sKOV8XuHQI0Rz4SjB9S46nqmGiMXUVQa_1Pm ...

  8. Ubuntu 小技巧

    一.获得当前文件夹的路径: 在目标文件夹下,按Ctrl+l此文件的路径会被选中 之后Ctrl+c复制.要复制到终端(Terminal),选中终端按鼠标的滚轮就粘贴到了Terminal命令行中了. 二. ...

  9. 609B Load Balancing

    题意:有n本书分m个类别,现在你要买两本不属于同一类别的书,问有多少种方案. #include<iostream> #include<cstdlib> #include< ...

  10. windows7开启虚拟wifi和虚拟无线AP的方法

         你可以开启windows 7的隐藏功能:虚拟WiFi和SoftAP(即虚拟无线AP),就可以让电脑变成无线路由器,实现共享上网. 1.点开始  所有程序   命令提示符右键管理员身份运行命令 ...