免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1462 | 回复: 0
打印 上一主题 下一主题

XML与C++对象的相互转化 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-09-09 13:53 |只看该作者 |倒序浏览

介绍
这个例子假设你在用一个XML文件来加载和保存你的应用程序配置,举例来说,有点像example4.xml。
有许多方法可以做到这点。例如,看看TinyBind项目:
http://sourceforge.net/projects/tinybind

这一节展示了一种普通老式的方法来使用XML加载和保存一个基本的对象结构。
建立你的对象类
从一些像这样的基本类开始:

[color="#ff0000"]#include
[color="#ff0000"]#include
[color="#0000ff"]using [color="#0000ff"]namespace [color="#0000ff"]std;

[color="#0000ff"]typedef [color="#0000ff"]std::map MessageMap;

[color="#008000"]// 基本的窗口抽象 - 仅仅是个示例
[color="#0000ff"]class WindowSettings
{
    [color="#0000ff"]public:
    [color="#0000ff"]int x,y,w,h;
    [color="#0000ff"]string name;
   
    WindowSettings()
        : x(0), y(0), w(100), h(100), name([color="#ff00ff"]"Untitled")
    {
    }
   
    WindowSettings([color="#0000ff"]int x, [color="#0000ff"]int y, [color="#0000ff"]int w, [color="#0000ff"]int h, const [color="#0000ff"]string& name)
    {
        [color="#0000ff"]this->x=x;
        [color="#0000ff"]this->y=y;
        [color="#0000ff"]this->w=w;
        [color="#0000ff"]this->h=h;
        [color="#0000ff"]this->name=name;
    }
};
 
[color="#0000ff"]class ConnectionSettings
{
    [color="#0000ff"]public:
    [color="#0000ff"]string [color="#808000"]ip;
    [color="#0000ff"]double timeout;
};

[color="#0000ff"]class AppSettings
{
    [color="#0000ff"]public:
    [color="#0000ff"]string m_name;
    MessageMap m_messages;
    [color="#0000ff"]list m_windows;
    ConnectionSettings m_connection;
   
    AppSettings() {}
   
    [color="#0000ff"]void save(const [color="#0000ff"]char* pFilename);
    [color="#0000ff"]void load(const [color="#0000ff"]char* pFilename);
   
    [color="#008000"]// 仅用于显示它是如何工作的
    [color="#0000ff"]void setDemoValues()
    {
        m_name=[color="#ff00ff"]"MyApp";
        m_messages.clear();
        m_messages[[color="#ff00ff"]"Welcome"]=[color="#ff00ff"]"Welcome to "+m_name;
        m_messages[[color="#ff00ff"]"Farewell"]=[color="#ff00ff"]"Thank you for using "+m_name;
        m_windows.clear();
        m_windows.push_back(WindowSettings(15,15,400,250,[color="#ff00ff"]"Main"));
        m_connection.ip=[color="#ff00ff"]"Unknown";
        m_connection.timeout=123.456;
    }
};
这是一个基本的mian(),它向我们展示了怎样创建一个默认的settings对象树,怎样保存并再次加载:

[color="#0000ff"]int main([color="#0000ff"]void)
{
    AppSettings settings;
   
    settings.save([color="#ff00ff"]"appsettings2.xml");
    settings.load([color="#ff00ff"]"appsettings2.xml");
    [color="#0000ff"]return 0;
}
接下来的main()展示了如何创建,修改,保存和加载一个settings结构:

[color="#0000ff"]int main([color="#0000ff"]void)
{
    [color="#008000"]// 区块:定制并保存settings
    {
        AppSettings settings;
        settings.m_name=[color="#ff00ff"]"HitchHikerApp";
        settings.m_messages[[color="#ff00ff"]"Welcome"]=[color="#ff00ff"]"Don’t Panic";
        settings.m_messages[[color="#ff00ff"]"Farewell"]=[color="#ff00ff"]"Thanks for all the fish";
        settings.m_windows.push_back(WindowSettings(15,25,300,250,[color="#ff00ff"]"BookFrame"));
        settings.m_connection.ip=[color="#ff00ff"]"192.168.0.77";
        settings.m_connection.timeout=42.0;
        
        settings.save([color="#ff00ff"]"appsettings2.xml");
    }
   
    [color="#008000"]// 区块:加载settings
    {
        AppSettings settings;
        settings.load([color="#ff00ff"]"appsettings2.xml");
        printf([color="#ff00ff"]"%s: %s\n", settings.m_name.c_str(),
        settings.m_messages[[color="#ff00ff"]"Welcome"].c_str());
        WindowSettings & w=settings.m_windows.front();
        printf([color="#ff00ff"]"%s: Show window ’%s’ at %d,%d (%d x %d)\n",
        settings.m_name.c_str(), w.name.c_str(), w.x, w.y, w.w, w.h);
        printf([color="#ff00ff"]"%s: %s\n", settings.m_name.c_str(),
                           settings.m_messages[[color="#ff00ff"]"Farewell"].c_str());
    }
    [color="#0000ff"]return 0;
}
当save()和load()完成后(请看下面),运行这个main()就会在控制台看到:

HitchHikerApp: Don’t Panic
HitchHikerApp: Show window ‘BookFrame’ at 15,25 (300 x 100)
HitchHikerApp: Thanks for all the fish
把C++状态编码成XML
有很多方法能够做到把文档对象保存到文件中,这就是其中一个:

[color="#0000ff"]void AppSettings::save(const [color="#0000ff"]char* pFilename)
{
    TiXmlDocument doc;
    TiXmlElement* msg;
    TiXmlComment * comment;
    [color="#0000ff"]string s;
    TiXmlDeclaration* decl = [color="#0000ff"]new TiXmlDeclaration( [color="#ff00ff"]"1.0", [color="#ff00ff"]"", [color="#ff00ff"]"" );
    doc.LinkEndChild( decl );
   
    TiXmlElement * root = [color="#0000ff"]new TiXmlElement(m_name.c_str());
    doc.LinkEndChild( root );
   
    comment = [color="#0000ff"]new TiXmlComment();
    s=[color="#ff00ff"]" Settings for "+m_name+[color="#ff00ff"]" ";
    comment->SetValue(s.c_str());
    root->LinkEndChild( comment );
   
    [color="#008000"]// 区块:messages
    {
        MessageMap::iterator iter;
        
        TiXmlElement * msgs = [color="#0000ff"]new TiXmlElement( [color="#ff00ff"]"Messages" );
        root->LinkEndChild( msgs );
        
        [color="#0000ff"]for (iter=m_messages.begin(); iter != m_messages.end(); iter++)
        {
            const [color="#0000ff"]string & key=(*iter).first;
            const [color="#0000ff"]string & value=(*iter).second;
            msg = [color="#0000ff"]new TiXmlElement(key.c_str());
            msg->LinkEndChild( [color="#0000ff"]new TiXmlText(value.c_str()));
            msgs->LinkEndChild( msg );
        }
    }
   
    [color="#008000"]// 区块:windows
    {
        TiXmlElement * windowsNode = [color="#0000ff"]new TiXmlElement( [color="#ff00ff"]"Windows" );
        root->LinkEndChild( windowsNode );
        
        [color="#0000ff"]list::iterator iter;
        
        [color="#0000ff"]for (iter=m_windows.begin(); iter != m_windows.end(); iter++)
        {
            const WindowSettings& w=*iter;
            
            TiXmlElement * window;
            window = [color="#0000ff"]new TiXmlElement( [color="#ff00ff"]"Window" );
            windowsNode->LinkEndChild( window );
            window->SetAttribute([color="#ff00ff"]"name", w.name.c_str());
            window->SetAttribute([color="#ff00ff"]"x", w.x);
            window->SetAttribute([color="#ff00ff"]"y", w.y);
            window->SetAttribute([color="#ff00ff"]"w", w.w);
            window->SetAttribute([color="#ff00ff"]"h", w.h);
        }
    }
   
    [color="#008000"]// 区块:connection
    {
        TiXmlElement * cxn = [color="#0000ff"]new TiXmlElement( [color="#ff00ff"]"Connection" );
        root->LinkEndChild( cxn );
        cxn->SetAttribute([color="#ff00ff"]"ip", m_connection.ip.c_str());
        cxn->SetDoubleAttribute([color="#ff00ff"]"timeout", m_connection.timeout);
    }
   
    doc.SaveFile(pFilename);
}
用修改过的main运行会生成这个文件:

   
   
      Thanks for all the fish
      Don't Panic
   
   
      
   
   

从XML中解码出状态
就像编码一样,也有许多方法可以让你从自己的C++对象结构中解码出XML。下面的方法使用了TiXmlHandles。

[color="#0000ff"]void AppSettings::load(const [color="#0000ff"]char* pFilename)
{
    TiXmlDocument doc(pFilename);
    [color="#0000ff"]if (!doc.LoadFile()) [color="#0000ff"]return;
   
    TiXmlHandle hDoc(&doc);
    TiXmlElement* pElem;
    TiXmlHandle hRoot(0);
   
    [color="#008000"]// 区块:name
    {
        pElem=hDoc.FirstChildElement().Element();
        [color="#008000"]// 必须有一个合法的根结点,如果没有则温文地处理(译注:直接返回)
        [color="#0000ff"]if (!pElem) [color="#0000ff"]return;
        m_name=pElem->Value();
        
        [color="#008000"]// 保存起来以备后面之用
        hRoot=TiXmlHandle(pElem);
    }
   
    [color="#008000"]// 区块:string table
    {
        m_messages.clear(); [color="#008000"]// 清空已有的table
        
        pElem=hRoot.FirstChild( [color="#ff00ff"]"Messages" ).FirstChild().Element();
        [color="#0000ff"]for( pElem; pElem; pElem=pElem->NextSiblingElement())
        {
            const [color="#0000ff"]char *pKey=pElem->Value();
            const [color="#0000ff"]char *pText=pElem->GetText();
            [color="#0000ff"]if (pKey && pText)
            {
                m_messages[pKey]=pText;
            }
        }
    }
   
    [color="#008000"]// 区块:windows
    {
        m_windows.clear(); [color="#008000"]// 清空链表
        
        TiXmlElement* pWindowNode=hRoot.FirstChild( [color="#ff00ff"]"Windows" )
                                       .FirstChild().Element();
        [color="#0000ff"]for( pWindowNode; pWindowNode;
             pWindowNode=pWindowNode->NextSiblingElement())
        {
            WindowSettings w;
            const [color="#0000ff"]char *pName=pWindowNode->Attribute([color="#ff00ff"]"name");
            [color="#0000ff"]if (pName) w.name=pName;
            
            pWindowNode->QueryIntAttribute([color="#ff00ff"]"x", &w.x); [color="#008000"]// 如果失败,原值保持现状
            pWindowNode->QueryIntAttribute([color="#ff00ff"]"y", &w.y);
            pWindowNode->QueryIntAttribute([color="#ff00ff"]"w", &w.w);
            pWindowNode->QueryIntAttribute([color="#ff00ff"]"hh", &w.h);
            
            m_windows.push_back(w);
        }
    }
   
    [color="#008000"]// 区块:connection
    {
        pElem=hRoot.FirstChild([color="#ff00ff"]"Connection").Element();
        [color="#0000ff"]if (pElem)
        {
            m_connection.ip=pElem->Attribute([color="#ff00ff"]"ip");
            pElem->QueryDoubleAttribute([color="#ff00ff"]"timeout",&m_connection.timeout);
        }
    }
}
dump_to_stdout的完整列表
下面是一个可直接运行的示例程序,使用上面提到过的递归遍历方式,可用来加载任意的XML文件并把结构输出到STDOUT上。

[color="#008000"]// 指南示例程序
[color="#ff0000"]#include [color="#ff00ff"]"stdafx.h"
[color="#ff0000"]#include [color="#ff00ff"]"tinyxml.h"

[color="#008000"]// ———————————————————————-
[color="#008000"]// STDOUT输出和缩进实用函数
[color="#008000"]// ———————————————————————-
const [color="#0000ff"]unsigned [color="#0000ff"]int NUM_INDENTS_PER_SPACE=2;

const [color="#0000ff"]char * getIndent( [color="#0000ff"]unsigned [color="#0000ff"]int numIndents )
{
    [color="#0000ff"]static const [color="#0000ff"]char * pINDENT=[color="#ff00ff"]" + ";
    [color="#0000ff"]static const [color="#0000ff"]unsigned [color="#0000ff"]int LENGTH=strlen( pINDENT );
    [color="#0000ff"]unsigned [color="#0000ff"]int n=numIndents*NUM_INDENTS_PER_SPACE;
    [color="#0000ff"]if ( n > LENGTH ) n = LENGTH;
   
    [color="#0000ff"]return &pINDENT[ LENGTH-n ];
}

[color="#008000"]// 与getIndent相同,但最后没有“+”
const [color="#0000ff"]char * getIndentAlt( [color="#0000ff"]unsigned [color="#0000ff"]int numIndents )
{
    [color="#0000ff"]static const [color="#0000ff"]char * pINDENT=[color="#ff00ff"]" ";
    [color="#0000ff"]static const [color="#0000ff"]unsigned [color="#0000ff"]int LENGTH=strlen( pINDENT );
    [color="#0000ff"]unsigned [color="#0000ff"]int n=numIndents*NUM_INDENTS_PER_SPACE;
    [color="#0000ff"]if ( n > LENGTH ) n = LENGTH;
   
    [color="#0000ff"]return &pINDENT[ LENGTH-n ];
}

[color="#0000ff"]int dump_attribs_to_stdout(TiXmlElement* pElement, [color="#0000ff"]unsigned [color="#0000ff"]int indent)
{
    [color="#0000ff"]if ( !pElement ) [color="#0000ff"]return 0;
   
    TiXmlAttribute* pAttrib=pElement->FirstAttribute();
    [color="#0000ff"]int i=0;
    [color="#0000ff"]int ival;
    [color="#0000ff"]double dval;
    const [color="#0000ff"]char* pIndent=getIndent(indent);
    printf([color="#ff00ff"]"\n");
    [color="#0000ff"]while (pAttrib)
    {
        printf( [color="#ff00ff"]"%s%s: value=[%s]", pIndent, pAttrib->Name(), pAttrib->Value());
        
        [color="#0000ff"]if (pAttrib->QueryIntValue(&ival)==TIXML_SUCCESS) printf( [color="#ff00ff"]" int=%d", ival);
        [color="#0000ff"]if (pAttrib->QueryDoubleValue(&dval)==TIXML_SUCCESS) printf( [color="#ff00ff"]" d=%1.1f", dval);
        printf( [color="#ff00ff"]"\n" );
        i++;
        pAttrib=pAttrib->Next();
    }
    [color="#0000ff"]return i;
}

[color="#0000ff"]void dump_to_stdout( TiXmlNode* pParent, [color="#0000ff"]unsigned [color="#0000ff"]int indent = 0 )
{
    [color="#0000ff"]if ( !pParent ) [color="#0000ff"]return;
   
    TiXmlNode* pChild;
    TiXmlText* pText;
    [color="#0000ff"]int t = pParent->Type();
    printf( [color="#ff00ff"]"%s", getIndent(indent));
    [color="#0000ff"]int num;
   
    [color="#0000ff"]switch ( t )
    {
        [color="#0000ff"]case TiXmlNode::DOCUMENT:
            printf( [color="#ff00ff"]"Document" );
            [color="#0000ff"]break;
        
        [color="#0000ff"]case TiXmlNode::ELEMENT:
            printf( [color="#ff00ff"]"Element [%s]", pParent->Value() );
            num=dump_attribs_to_stdout(pParent->ToElement(), indent+1);
            [color="#0000ff"]switch(num)
            {
                [color="#0000ff"]case 0: printf( [color="#ff00ff"]" (No attributes)"); [color="#0000ff"]break;
                [color="#0000ff"]case 1: printf( [color="#ff00ff"]"%s1 attribute", getIndentAlt(indent)); [color="#0000ff"]break;
                [color="#0000ff"]default: printf( [color="#ff00ff"]"%s%d attributes", getIndentAlt(indent), num); [color="#0000ff"]break;
            }
            [color="#0000ff"]break;
        
        [color="#0000ff"]case TiXmlNode::COMMENT:
            printf( [color="#ff00ff"]"Comment: [%s]", pParent->Value());
            [color="#0000ff"]break;
        
        [color="#0000ff"]case TiXmlNode::UNKNOWN:
            printf( [color="#ff00ff"]"Unknown" );
            [color="#0000ff"]break;
        
        [color="#0000ff"]case TiXmlNode::TEXT:
            pText = pParent->ToText();
            printf( [color="#ff00ff"]"Text: [%s]", pText->Value() );
            [color="#0000ff"]break;
        
        [color="#0000ff"]case TiXmlNode::DECLARATION:
            printf( [color="#ff00ff"]"Declaration" );
            [color="#0000ff"]break;
            [color="#0000ff"]default:
            [color="#0000ff"]break;
    }
    printf( [color="#ff00ff"]"\n" );
    [color="#0000ff"]for ( pChild = pParent->FirstChild(); pChild != 0; pChild = pChild->NextSibling())
    {
        dump_to_stdout( pChild, indent+1 );
    }
}

[color="#008000"]// 加载指定的文件并把它的结构输出到STDOUT上
[color="#0000ff"]void dump_to_stdout(const [color="#0000ff"]char* pFilename)
{
    TiXmlDocument doc(pFilename);
    [color="#0000ff"]bool loadOkay = doc.LoadFile();
    [color="#0000ff"]if (loadOkay)
    {
        printf([color="#ff00ff"]"\n%s:\n", pFilename);
        dump_to_stdout( &doc );
    }
    [color="#0000ff"]else
    {
        printf([color="#ff00ff"]"Failed to load file \"%s\”\n", pFilename);
    }
}

[color="#008000"]// ———————————————————————-
[color="#008000"]// main(),打印出从命令行指定的文件
[color="#008000"]// ———————————————————————-
[color="#0000ff"]int main([color="#0000ff"]int argc, [color="#0000ff"]char* argv[])
{
    [color="#0000ff"]for ([color="#0000ff"]int i=1; iC:\dev\tinyxml> Debug\tinyxml_1.exe example1.xml
example1.xml:
Document
+ Declaration
+ Element [Hello]
  (No attributes)
  + Text: [World]
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/102400/showart_2048953.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP