- 论坛徽章:
- 0
|
介绍
这个例子假设你在用一个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 |
|