📄 tutorial0.html
字号:
AppSettings settings;
settings.save("appsettings2.xml");
settings.load("appsettings2.xml");
return 0;
}
</pre></div><p>
The following main() shows creation, modification, saving and then loading of a settings structure:<p>
<div class="fragment"><pre class="fragment">int main(void)
{
// block: customise and save settings
{
AppSettings settings;
settings.m_name="HitchHikerApp";
settings.m_messages["Welcome"]="Don't Panic";
settings.m_messages["Farewell"]="Thanks for all the fish";
settings.m_windows.push_back(WindowSettings(15,25,300,250,"BookFrame"));
settings.m_connection.ip="192.168.0.77";
settings.m_connection.timeout=42.0;
settings.save("appsettings2.xml");
}
// block: load settings
{
AppSettings settings;
settings.load("appsettings2.xml");
printf("%s: %s\n", settings.m_name.c_str(),
settings.m_messages["Welcome"].c_str());
WindowSettings & w=settings.m_windows.front();
printf("%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("%s: %s\n", settings.m_name.c_str(), settings.m_messages["Farewell"].c_str());
}
return 0;
}
</pre></div><p>
When the save() and load() are completed (see below), running this main() displays on the console:<p>
<div class="fragment"><pre class="fragment">HitchHikerApp: Don't Panic
HitchHikerApp: Show window 'BookFrame' at 15,25 (300 x 100)
HitchHikerApp: Thanks for all the fish
</pre></div><p>
<h2>Encode C++ state as XML </h2>
<p>
There are lots of different ways to approach saving this to a file. Here's one:<p>
<div class="fragment"><pre class="fragment">void AppSettings::save(const char* pFilename)
{
TiXmlDocument doc;
TiXmlElement* msg;
TiXmlComment * comment;
string s;
TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" );
doc.LinkEndChild( decl );
TiXmlElement * root = new TiXmlElement(m_name.c_str());
doc.LinkEndChild( root );
comment = new TiXmlComment();
s=" Settings for "+m_name+" ";
comment->SetValue(s.c_str());
root->LinkEndChild( comment );
// block: messages
{
MessageMap::iterator iter;
TiXmlElement * msgs = new TiXmlElement( "Messages" );
root->LinkEndChild( msgs );
for (iter=m_messages.begin(); iter != m_messages.end(); iter++)
{
const string & key=(*iter).first;
const string & value=(*iter).second;
msg = new TiXmlElement(key.c_str());
msg->LinkEndChild( new TiXmlText(value.c_str()));
msgs->LinkEndChild( msg );
}
}
// block: windows
{
TiXmlElement * windowsNode = new TiXmlElement( "Windows" );
root->LinkEndChild( windowsNode );
list<WindowSettings>::iterator iter;
for (iter=m_windows.begin(); iter != m_windows.end(); iter++)
{
const WindowSettings& w=*iter;
TiXmlElement * window;
window = new TiXmlElement( "Window" );
windowsNode->LinkEndChild( window );
window->SetAttribute("name", w.name.c_str());
window->SetAttribute("x", w.x);
window->SetAttribute("y", w.y);
window->SetAttribute("w", w.w);
window->SetAttribute("h", w.h);
}
}
// block: connection
{
TiXmlElement * cxn = new TiXmlElement( "Connection" );
root->LinkEndChild( cxn );
cxn->SetAttribute("ip", m_connection.ip.c_str());
cxn->SetDoubleAttribute("timeout", m_connection.timeout);
}
doc.SaveFile(pFilename);
}
</pre></div><p>
Running this with the modified main produces this file:<p>
<div class="fragment"><pre class="fragment"><?xml version="1.0" ?>
<HitchHikerApp>
<!-- Settings for HitchHikerApp -->
<Messages>
<Farewell>Thanks for all the fish</Farewell>
<Welcome>Don&apos;t Panic</Welcome>
</Messages>
<Windows>
<Window name="BookFrame" x="15" y="25" w="300" h="250" />
</Windows>
<Connection ip="192.168.0.77" timeout="42.000000" />
</HitchHikerApp>
</pre></div><p>
<h2>Decoding state from XML </h2>
<p>
As with encoding objects, there are a number of approaches to decoding XML into your own C++ object structure. The following approach uses TiXmlHandles.<p>
<div class="fragment"><pre class="fragment">void AppSettings::load(const char* pFilename)
{
TiXmlDocument doc(pFilename);
if (!doc.LoadFile()) return;
TiXmlHandle hDoc(&doc);
TiXmlElement* pElem;
TiXmlHandle hRoot(0);
// block: name
{
pElem=hDoc.FirstChildElement().Element();
// should always have a valid root but handle gracefully if it does
if (!pElem) return;
m_name=pElem->Value();
// save this for later
hRoot=TiXmlHandle(pElem);
}
// block: string table
{
m_messages.clear(); // trash existing table
pElem=hRoot.FirstChild( "Messages" ).FirstChild().Element();
for( pElem; pElem; pElem=pElem->NextSiblingElement())
{
const char *pKey=pElem->Value();
const char *pText=pElem->GetText();
if (pKey && pText)
{
m_messages[pKey]=pText;
}
}
}
// block: windows
{
m_windows.clear(); // trash existing list
TiXmlElement* pWindowNode=hRoot.FirstChild( "Windows" ).FirstChild().Element();
for( pWindowNode; pWindowNode; pWindowNode=pWindowNode->NextSiblingElement())
{
WindowSettings w;
const char *pName=pWindowNode->Attribute("name");
if (pName) w.name=pName;
pWindowNode->QueryIntAttribute("x", &w.x); // If this fails, original value is left as-is
pWindowNode->QueryIntAttribute("y", &w.y);
pWindowNode->QueryIntAttribute("w", &w.w);
pWindowNode->QueryIntAttribute("hh", &w.h);
m_windows.push_back(w);
}
}
// block: connection
{
pElem=hRoot.FirstChild("Connection").Element();
if (pElem)
{
m_connection.ip=pElem->Attribute("ip");
pElem->QueryDoubleAttribute("timeout",&m_connection.timeout);
}
}
}
</pre></div><p>
<h1>Full listing for dump_to_stdout </h1>
<p>
Below is a copy-and-paste demo program for loading arbitrary XML files and dumping the structure to STDOUT using the recursive traversal listed above.<p>
<div class="fragment"><pre class="fragment">// tutorial demo program
#include "stdafx.h"
#include "tinyxml.h"
// ----------------------------------------------------------------------
// STDOUT dump and indenting utility functions
// ----------------------------------------------------------------------
const unsigned int NUM_INDENTS_PER_SPACE=2;
const char * getIndent( unsigned int numIndents )
{
static const char * pINDENT=" + ";
static const unsigned int LENGTH=strlen( pINDENT );
unsigned int n=numIndents*NUM_INDENTS_PER_SPACE;
if ( n > LENGTH ) n = LENGTH;
return &pINDENT[ LENGTH-n ];
}
// same as getIndent but no "+" at the end
const char * getIndentAlt( unsigned int numIndents )
{
static const char * pINDENT=" ";
static const unsigned int LENGTH=strlen( pINDENT );
unsigned int n=numIndents*NUM_INDENTS_PER_SPACE;
if ( n > LENGTH ) n = LENGTH;
return &pINDENT[ LENGTH-n ];
}
int dump_attribs_to_stdout(TiXmlElement* pElement, unsigned int indent)
{
if ( !pElement ) return 0;
TiXmlAttribute* pAttrib=pElement->FirstAttribute();
int i=0;
int ival;
double dval;
const char* pIndent=getIndent(indent);
printf("\n");
while (pAttrib)
{
printf( "%s%s: value=[%s]", pIndent, pAttrib->Name(), pAttrib->Value());
if (pAttrib->QueryIntValue(&ival)==TIXML_SUCCESS) printf( " int=%d", ival);
if (pAttrib->QueryDoubleValue(&dval)==TIXML_SUCCESS) printf( " d=%1.1f", dval);
printf( "\n" );
i++;
pAttrib=pAttrib->Next();
}
return i;
}
void dump_to_stdout( TiXmlNode* pParent, unsigned int indent = 0 )
{
if ( !pParent ) return;
TiXmlNode* pChild;
TiXmlText* pText;
int t = pParent->Type();
printf( "%s", getIndent(indent));
int num;
switch ( t )
{
case TiXmlNode::DOCUMENT:
printf( "Document" );
break;
case TiXmlNode::ELEMENT:
printf( "Element [%s]", pParent->Value() );
num=dump_attribs_to_stdout(pParent->ToElement(), indent+1);
switch(num)
{
case 0: printf( " (No attributes)"); break;
case 1: printf( "%s1 attribute", getIndentAlt(indent)); break;
default: printf( "%s%d attributes", getIndentAlt(indent), num); break;
}
break;
case TiXmlNode::COMMENT:
printf( "Comment: [%s]", pParent->Value());
break;
case TiXmlNode::UNKNOWN:
printf( "Unknown" );
break;
case TiXmlNode::TEXT:
pText = pParent->ToText();
printf( "Text: [%s]", pText->Value() );
break;
case TiXmlNode::DECLARATION:
printf( "Declaration" );
break;
default:
break;
}
printf( "\n" );
for ( pChild = pParent->FirstChild(); pChild != 0; pChild = pChild->NextSibling())
{
dump_to_stdout( pChild, indent+1 );
}
}
// load the named file and dump its structure to STDOUT
void dump_to_stdout(const char* pFilename)
{
TiXmlDocument doc(pFilename);
bool loadOkay = doc.LoadFile();
if (loadOkay)
{
printf("\n%s:\n", pFilename);
dump_to_stdout( &doc ); // defined later in the tutorial
}
else
{
printf("Failed to load file \"%s\"\n", pFilename);
}
}
// ----------------------------------------------------------------------
// main() for printing files named on the command line
// ----------------------------------------------------------------------
int main(int argc, char* argv[])
{
for (int i=1; i<argc; i++)
{
dump_to_stdout(argv[i]);
}
return 0;
}
</pre></div><p>
Run this from the command line or a DOS window, e.g.:<p>
<div class="fragment"><pre class="fragment">C:\dev\tinyxml> Debug\tinyxml_1.exe example1.xml
example1.xml:
Document
+ Declaration
+ Element [Hello]
(No attributes)
+ Text: [World]
</pre></div><p>
<em> Authors and Changes <ul>
<li>
Written by Ellers, April, May, June 2005 </li>
<li>
Minor edits and integration into doc system, Lee Thomason September 2005 </li>
<li>
Updated by Ellers, October 2005 </li>
</ul>
</em> <hr size="1"><address style="align: right;"><small>Generated on Sun Jan 15 23:12:05 2006 for TinyXml by
<a href="http://www.doxygen.org/index.html">
<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.4.4 </small></address>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -