source: scenarios/MyFriend/Watching2Players/iCatChess/XML/TinyXML252/docs/tutorial0.html @ 336

Revision 336, 22.4 KB checked in by pedro.cuba, 10 years ago (diff)
Line 
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
3<title>TinyXml: TinyXML Tutorial</title>
4<link href="doxygen.css" rel="stylesheet" type="text/css">
5<link href="tabs.css" rel="stylesheet" type="text/css">
6</head><body>
7<!-- Generated by Doxygen 1.4.7 -->
8<div class="tabs">
9  <ul>
10    <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
11    <li><a href="annotated.html"><span>Classes</span></a></li>
12    <li><a href="files.html"><span>Files</span></a></li>
13    <li><a href="pages.html"><span>Related&nbsp;Pages</span></a></li>
14  </ul></div>
15<div class="nav">
16<a class="el" href="index.html">index</a></div>
17<h1><a class="anchor" name="tutorial0">TinyXML Tutorial</a></h1><h1>What is this? </h1>
18<p>
19This tutorial has a few tips and suggestions on how to use TinyXML effectively.<p>
20I've also tried to include some C++ tips like how to convert strings to integers and vice versa. This isn't anything to do with TinyXML itself, but it may helpful for your project so I've put it in anyway.<p>
21If you don't know basic C++ concepts this tutorial won't be useful. Likewise if you don't know what a DOM is, look elsewhere first.<p>
22<h1>Before we start </h1>
23<p>
24Some example XML datasets/files will be used.<p>
25example1.xml:<p>
26<div class="fragment"><pre class="fragment">&lt;?xml version="1.0" ?&gt;
27&lt;Hello&gt;World&lt;/Hello&gt;
28</pre></div><p>
29example2.xml:<p>
30<div class="fragment"><pre class="fragment">&lt;?xml version="1.0" ?&gt;
31&lt;poetry&gt;
32        &lt;verse&gt;
33                Alas
34                  Great World
35                        Alas (again)
36        &lt;/verse&gt;
37&lt;/poetry&gt;
38</pre></div><p>
39example3.xml:<p>
40<div class="fragment"><pre class="fragment">&lt;?xml version="1.0" ?&gt;
41&lt;shapes&gt;
42        &lt;circle name="int-based" x="20" y="30" r="50" /&gt;
43        &lt;point name="float-based" x="3.5" y="52.1" /&gt;
44&lt;/shapes&gt;
45</pre></div><p>
46example4.xml<p>
47<div class="fragment"><pre class="fragment">&lt;?xml version="1.0" ?&gt;
48&lt;MyApp&gt;
49    &lt;!-- Settings for MyApp --&gt;
50    &lt;Messages&gt;
51        &lt;Welcome&gt;Welcome to MyApp&lt;/Welcome&gt;
52        &lt;Farewell&gt;Thank you for using MyApp&lt;/Farewell&gt;
53    &lt;/Messages&gt;
54    &lt;Windows&gt;
55        &lt;Window name="MainFrame" x="5" y="15" w="400" h="250" /&gt;
56    &lt;/Windows&gt;
57    &lt;Connection ip="192.168.0.1" timeout="123.456000" /&gt;
58&lt;/MyApp&gt;
59</pre></div><p>
60<h1>Getting Started </h1>
61<p>
62<h2>Load XML from a file </h2>
63<p>
64The simplest way to load a file into a TinyXML DOM is:<p>
65<div class="fragment"><pre class="fragment">TiXmlDocument doc( "demo.xml" );
66doc.LoadFile();
67</pre></div><p>
68A more real-world usage is shown below. This will load the file and display the contents to STDOUT:<p>
69<div class="fragment"><pre class="fragment">// load the named file and dump its structure to STDOUT
70void dump_to_stdout(const char* pFilename)
71{
72        TiXmlDocument doc(pFilename);
73        bool loadOkay = doc.LoadFile();
74        if (loadOkay)
75        {
76                printf("\n%s:\n", pFilename);
77                dump_to_stdout( &amp;doc ); // defined later in the tutorial
78        }
79        else
80        {
81                printf("Failed to load file \"%s\"\n", pFilename);
82        }
83}
84</pre></div><p>
85A simple demonstration of this function is to use a main like this:<p>
86<div class="fragment"><pre class="fragment">int main(void)
87{
88        dump_to_stdout("example1.xml");
89        return 0;
90}
91</pre></div><p>
92Recall that Example 1 XML is:<p>
93<div class="fragment"><pre class="fragment">&lt;?xml version="1.0" ?&gt;
94&lt;Hello&gt;World&lt;/Hello&gt;
95</pre></div><p>
96Running the program with this XML will display this in the console/DOS window:<p>
97<div class="fragment"><pre class="fragment">DOCUMENT
98+ DECLARATION
99+ ELEMENT Hello
100  + TEXT[World]
101</pre></div><p>
102The ``dump_to_stdout`` function is defined later in this tutorial and is useful if you want to understand recursive traversal of a DOM.<p>
103<h2>Building Documents Programatically </h2>
104<p>
105This is how to build Example 1 pragmatically:<p>
106<div class="fragment"><pre class="fragment">void build_simple_doc( )
107{
108        // Make xml: &lt;?xml ..&gt;&lt;Hello&gt;World&lt;/Hello&gt;
109        TiXmlDocument doc;
110        TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );
111        TiXmlElement * element = new TiXmlElement( "Hello" );
112        TiXmlText * text = new TiXmlText( "World" );
113        element-&gt;LinkEndChild( text );
114        doc.LinkEndChild( decl );
115        doc.LinkEndChild( element );
116        doc.SaveFile( "madeByHand.xml" );
117}
118</pre></div><p>
119This can be loaded and displayed on the console with:<p>
120<div class="fragment"><pre class="fragment">dump_to_stdout("madeByHand.xml"); // this func defined later in the tutorial
121</pre></div><p>
122and you'll see it is identical to Example 1:<p>
123<div class="fragment"><pre class="fragment">madeByHand.xml:
124Document
125+ Declaration
126+ Element [Hello]
127  + Text: [World]
128</pre></div><p>
129This code produces exactly the same XML DOM but it shows a different ordering to node creation and linking:<p>
130<div class="fragment"><pre class="fragment">void write_simple_doc2( )
131{
132        // same as write_simple_doc1 but add each node
133        // as early as possible into the tree.
134
135        TiXmlDocument doc;
136        TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );
137        doc.LinkEndChild( decl );
138       
139        TiXmlElement * element = new TiXmlElement( "Hello" );
140        doc.LinkEndChild( element );
141       
142        TiXmlText * text = new TiXmlText( "World" );
143        element-&gt;LinkEndChild( text );
144       
145        doc.SaveFile( "madeByHand2.xml" );
146}
147</pre></div><p>
148Both of these produce the same XML, namely:<p>
149<div class="fragment"><pre class="fragment">&lt;?xml version="1.0" ?&gt;
150&lt;Hello&gt;World&lt;/Hello&gt;
151</pre></div><p>
152Or in structure form:<p>
153<div class="fragment"><pre class="fragment">DOCUMENT
154+ DECLARATION
155+ ELEMENT Hello
156  + TEXT[World]
157</pre></div><p>
158<h2>Attributes </h2>
159<p>
160Given an existing node, settings attributes is easy:<p>
161<div class="fragment"><pre class="fragment">window = new TiXmlElement( "Demo" ); 
162window-&gt;SetAttribute("name", "Circle");
163window-&gt;SetAttribute("x", 5);
164window-&gt;SetAttribute("y", 15);
165window-&gt;SetDoubleAttribute("radius", 3.14159);
166</pre></div><p>
167You can it also work with the <a class="el" href="classTiXmlAttribute.html">TiXmlAttribute</a> objects if you want.<p>
168The following code shows one way (not the only way) to get all attributes of an element, print the name and string value, and if the value can be converted to an integer or double, print that value too:<p>
169<div class="fragment"><pre class="fragment">// print all attributes of pElement.
170// returns the number of attributes printed
171int dump_attribs_to_stdout(TiXmlElement* pElement, unsigned int indent)
172{
173        if ( !pElement ) return 0;
174
175        TiXmlAttribute* pAttrib=pElement-&gt;FirstAttribute();
176        int i=0;
177        int ival;
178        double dval;
179        const char* pIndent=getIndent(indent);
180        printf("\n");
181        while (pAttrib)
182        {
183                printf( "%s%s: value=[%s]", pIndent, pAttrib-&gt;Name(), pAttrib-&gt;Value());
184
185                if (pAttrib-&gt;QueryIntValue(&amp;ival)==TIXML_SUCCESS)    printf( " int=%d", ival);
186                if (pAttrib-&gt;QueryDoubleValue(&amp;dval)==TIXML_SUCCESS) printf( " d=%1.1f", dval);
187                printf( "\n" );
188                i++;
189                pAttrib=pAttrib-&gt;Next();
190        }
191        return i;
192}
193</pre></div><p>
194<h2>Writing a document to a file </h2>
195<p>
196Writing a pre-built DOM to a file is trivial:<p>
197<div class="fragment"><pre class="fragment">doc.SaveFile( saveFilename ); 
198</pre></div><p>
199Recall, for example, example 4:<p>
200<div class="fragment"><pre class="fragment">&lt;?xml version="1.0" ?&gt;
201&lt;MyApp&gt;
202    &lt;!-- Settings for MyApp --&gt;
203    &lt;Messages&gt;
204        &lt;Welcome&gt;Welcome to MyApp&lt;/Welcome&gt;
205        &lt;Farewell&gt;Thank you for using MyApp&lt;/Farewell&gt;
206    &lt;/Messages&gt;
207    &lt;Windows&gt;
208        &lt;Window name="MainFrame" x="5" y="15" w="400" h="250" /&gt;
209    &lt;/Windows&gt;
210    &lt;Connection ip="192.168.0.1" timeout="123.456000" /&gt;
211&lt;/MyApp&gt;
212</pre></div><p>
213The following function builds this DOM and writes the file "appsettings.xml":<p>
214<div class="fragment"><pre class="fragment">void write_app_settings_doc( ) 
215
216        TiXmlDocument doc; 
217        TiXmlElement* msg;
218        TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" ); 
219        doc.LinkEndChild( decl ); 
220 
221        TiXmlElement * root = new TiXmlElement( "MyApp" ); 
222        doc.LinkEndChild( root ); 
223
224        TiXmlComment * comment = new TiXmlComment();
225        comment-&gt;SetValue(" Settings for MyApp " ); 
226        root-&gt;LinkEndChild( comment ); 
227 
228        TiXmlElement * msgs = new TiXmlElement( "Messages" ); 
229        root-&gt;LinkEndChild( msgs ); 
230 
231        msg = new TiXmlElement( "Welcome" ); 
232        msg-&gt;LinkEndChild( new TiXmlText( "Welcome to MyApp" )); 
233        msgs-&gt;LinkEndChild( msg ); 
234 
235        msg = new TiXmlElement( "Farewell" ); 
236        msg-&gt;LinkEndChild( new TiXmlText( "Thank you for using MyApp" )); 
237        msgs-&gt;LinkEndChild( msg ); 
238 
239        TiXmlElement * windows = new TiXmlElement( "Windows" ); 
240        root-&gt;LinkEndChild( windows ); 
241
242        TiXmlElement * window;
243        window = new TiXmlElement( "Window" ); 
244        windows-&gt;LinkEndChild( window ); 
245        window-&gt;SetAttribute("name", "MainFrame");
246        window-&gt;SetAttribute("x", 5);
247        window-&gt;SetAttribute("y", 15);
248        window-&gt;SetAttribute("w", 400);
249        window-&gt;SetAttribute("h", 250);
250
251        TiXmlElement * cxn = new TiXmlElement( "Connection" ); 
252        root-&gt;LinkEndChild( cxn ); 
253        cxn-&gt;SetAttribute("ip", "192.168.0.1");
254        cxn-&gt;SetDoubleAttribute("timeout", 123.456); // floating point attrib
255       
256        dump_to_stdout( &amp;doc );
257        doc.SaveFile( "appsettings.xml" ); 
258}
259</pre></div><p>
260The dump_to_stdout function will show this structure:<p>
261<div class="fragment"><pre class="fragment">Document
262+ Declaration
263+ Element [MyApp]
264 (No attributes)
265  + Comment: [ Settings for MyApp ]
266  + Element [Messages]
267 (No attributes)
268    + Element [Welcome]
269 (No attributes)
270      + Text: [Welcome to MyApp]
271    + Element [Farewell]
272 (No attributes)
273      + Text: [Thank you for using MyApp]
274  + Element [Windows]
275 (No attributes)
276    + Element [Window]
277      + name: value=[MainFrame]
278      + x: value=[5] int=5 d=5.0
279      + y: value=[15] int=15 d=15.0
280      + w: value=[400] int=400 d=400.0
281      + h: value=[250] int=250 d=250.0
282      5 attributes
283  + Element [Connection]
284    + ip: value=[192.168.0.1] int=192 d=192.2
285    + timeout: value=[123.456000] int=123 d=123.5
286    2 attributes
287</pre></div><p>
288I was surprised that TinyXml, by default, writes the XML in what other APIs call a "pretty" format - it modifies the whitespace of text of elements that contain other nodes so that writing the tree includes an indication of nesting level.<p>
289I haven't looked yet to see if there is a way to turn off indenting when writing a file - its bound to be easy.<p>
290[Lee: It's easy in STL mode, just use cout &lt;&lt; myDoc. Non-STL mode is always in "pretty" format. Adding a switch would be a nice feature and has been requested.]<p>
291<h1>XML to/from C++ objects </h1>
292<p>
293<h2>Intro </h2>
294<p>
295This example assumes you're loading and saving your app settings in an XML file, e.g. something like example4.xml.<p>
296There are a number of ways to do this. For example, look into the TinyBind project at <a href="http://sourceforge.net/projects/tinybind">http://sourceforge.net/projects/tinybind</a><p>
297This section shows a plain-old approach to loading and saving a basic object structure using XML.<p>
298<h2>Set up your object classes </h2>
299<p>
300Start off with some basic classes like these:<p>
301<div class="fragment"><pre class="fragment">#include &lt;string&gt;
302#include &lt;map&gt;
303using namespace std;
304
305typedef std::map&lt;std::string,std::string&gt; MessageMap;
306
307// a basic window abstraction - demo purposes only
308class WindowSettings
309{
310public:
311        int x,y,w,h;
312        string name;
313
314        WindowSettings()
315                : x(0), y(0), w(100), h(100), name("Untitled")
316        {
317        }
318
319        WindowSettings(int x, int y, int w, int h, const string&amp; name)
320        {
321                this-&gt;x=x;
322                this-&gt;y=y;
323                this-&gt;w=w;
324                this-&gt;h=h;
325                this-&gt;name=name;
326        }
327};
328
329class ConnectionSettings
330{
331public:
332        string ip;
333        double timeout;
334};
335
336class AppSettings
337{
338public:
339        string m_name;
340        MessageMap m_messages;
341        list&lt;WindowSettings&gt; m_windows;
342        ConnectionSettings m_connection;
343
344        AppSettings() {}
345
346        void save(const char* pFilename);
347        void load(const char* pFilename);
348       
349        // just to show how to do it
350        void setDemoValues()
351        {
352                m_name="MyApp";
353                m_messages.clear();
354                m_messages["Welcome"]="Welcome to "+m_name;
355                m_messages["Farewell"]="Thank you for using "+m_name;
356                m_windows.clear();
357                m_windows.push_back(WindowSettings(15,15,400,250,"Main"));
358                m_connection.ip="Unknown";
359                m_connection.timeout=123.456;
360        }
361};
362</pre></div><p>
363This is a basic main() that shows how to create a default settings object tree, save it and load it again:<p>
364<div class="fragment"><pre class="fragment">int main(void)
365{
366        AppSettings settings;
367       
368        settings.save("appsettings2.xml");
369        settings.load("appsettings2.xml");
370        return 0;
371}
372</pre></div><p>
373The following main() shows creation, modification, saving and then loading of a settings structure:<p>
374<div class="fragment"><pre class="fragment">int main(void)
375{
376        // block: customise and save settings
377        {
378                AppSettings settings;
379                settings.m_name="HitchHikerApp";
380                settings.m_messages["Welcome"]="Don't Panic";
381                settings.m_messages["Farewell"]="Thanks for all the fish";
382                settings.m_windows.push_back(WindowSettings(15,25,300,250,"BookFrame"));
383                settings.m_connection.ip="192.168.0.77";
384                settings.m_connection.timeout=42.0;
385
386                settings.save("appsettings2.xml");
387        }
388       
389        // block: load settings
390        {
391                AppSettings settings;
392                settings.load("appsettings2.xml");
393                printf("%s: %s\n", settings.m_name.c_str(),
394                        settings.m_messages["Welcome"].c_str());
395                WindowSettings &amp; w=settings.m_windows.front();
396                printf("%s: Show window '%s' at %d,%d (%d x %d)\n",
397                        settings.m_name.c_str(), w.name.c_str(), w.x, w.y, w.w, w.h);
398                printf("%s: %s\n", settings.m_name.c_str(), settings.m_messages["Farewell"].c_str());
399        }
400        return 0;
401}
402</pre></div><p>
403When the save() and load() are completed (see below), running this main() displays on the console:<p>
404<div class="fragment"><pre class="fragment">HitchHikerApp: Don't Panic
405HitchHikerApp: Show window 'BookFrame' at 15,25 (300 x 100)
406HitchHikerApp: Thanks for all the fish
407</pre></div><p>
408<h2>Encode C++ state as XML </h2>
409<p>
410There are lots of different ways to approach saving this to a file. Here's one:<p>
411<div class="fragment"><pre class="fragment">void AppSettings::save(const char* pFilename)
412{
413        TiXmlDocument doc; 
414        TiXmlElement* msg;
415        TiXmlComment * comment;
416        string s;
417        TiXmlDeclaration* decl = new TiXmlDeclaration( "1.0", "", "" ); 
418        doc.LinkEndChild( decl );
419 
420        TiXmlElement * root = new TiXmlElement(m_name.c_str()); 
421        doc.LinkEndChild( root ); 
422
423        comment = new TiXmlComment();
424        s=" Settings for "+m_name+" ";
425        comment-&gt;SetValue(s.c_str()); 
426        root-&gt;LinkEndChild( comment ); 
427
428        // block: messages
429        {
430                MessageMap::iterator iter;
431
432                TiXmlElement * msgs = new TiXmlElement( "Messages" ); 
433                root-&gt;LinkEndChild( msgs ); 
434 
435                for (iter=m_messages.begin(); iter != m_messages.end(); iter++)
436                {
437                        const string &amp; key=(*iter).first;
438                        const string &amp; value=(*iter).second;
439                        msg = new TiXmlElement(key.c_str()); 
440                        msg-&gt;LinkEndChild( new TiXmlText(value.c_str())); 
441                        msgs-&gt;LinkEndChild( msg ); 
442                }
443        }
444
445        // block: windows
446        {
447                TiXmlElement * windowsNode = new TiXmlElement( "Windows" ); 
448                root-&gt;LinkEndChild( windowsNode ); 
449
450                list&lt;WindowSettings&gt;::iterator iter;
451
452                for (iter=m_windows.begin(); iter != m_windows.end(); iter++)
453                {
454                        const WindowSettings&amp; w=*iter;
455
456                        TiXmlElement * window;
457                        window = new TiXmlElement( "Window" ); 
458                        windowsNode-&gt;LinkEndChild( window ); 
459                        window-&gt;SetAttribute("name", w.name.c_str());
460                        window-&gt;SetAttribute("x", w.x);
461                        window-&gt;SetAttribute("y", w.y);
462                        window-&gt;SetAttribute("w", w.w);
463                        window-&gt;SetAttribute("h", w.h);
464                }
465        }
466
467        // block: connection
468        {
469                TiXmlElement * cxn = new TiXmlElement( "Connection" ); 
470                root-&gt;LinkEndChild( cxn ); 
471                cxn-&gt;SetAttribute("ip", m_connection.ip.c_str());
472                cxn-&gt;SetDoubleAttribute("timeout", m_connection.timeout);
473        }
474
475        doc.SaveFile(pFilename); 
476}
477</pre></div><p>
478Running this with the modified main produces this file:<p>
479<div class="fragment"><pre class="fragment">&lt;?xml version="1.0" ?&gt;
480&lt;HitchHikerApp&gt;
481    &lt;!-- Settings for HitchHikerApp --&gt;
482    &lt;Messages&gt;
483        &lt;Farewell&gt;Thanks for all the fish&lt;/Farewell&gt;
484        &lt;Welcome&gt;Don&amp;apos;t Panic&lt;/Welcome&gt;
485    &lt;/Messages&gt;
486    &lt;Windows&gt;
487        &lt;Window name="BookFrame" x="15" y="25" w="300" h="250" /&gt;
488    &lt;/Windows&gt;
489    &lt;Connection ip="192.168.0.77" timeout="42.000000" /&gt;
490&lt;/HitchHikerApp&gt;
491</pre></div><p>
492<h2>Decoding state from XML </h2>
493<p>
494As with encoding objects, there are a number of approaches to decoding XML into your own C++ object structure. The following approach uses TiXmlHandles.<p>
495<div class="fragment"><pre class="fragment">void AppSettings::load(const char* pFilename)
496{
497        TiXmlDocument doc(pFilename);
498        if (!doc.LoadFile()) return;
499
500        TiXmlHandle hDoc(&amp;doc);
501        TiXmlElement* pElem;
502        TiXmlHandle hRoot(0);
503
504        // block: name
505        {
506                pElem=hDoc.FirstChildElement().Element();
507                // should always have a valid root but handle gracefully if it does
508                if (!pElem) return;
509                m_name=pElem-&gt;Value();
510
511                // save this for later
512                hRoot=TiXmlHandle(pElem);
513        }
514
515        // block: string table
516        {
517                m_messages.clear(); // trash existing table
518
519                pElem=hRoot.FirstChild( "Messages" ).FirstChild().Element();
520                for( pElem; pElem; pElem=pElem-&gt;NextSiblingElement())
521                {
522                        const char *pKey=pElem-&gt;Value();
523                        const char *pText=pElem-&gt;GetText();
524                        if (pKey &amp;&amp; pText)
525                        {
526                                m_messages[pKey]=pText;
527                        }
528                }
529        }
530
531        // block: windows
532        {
533                m_windows.clear(); // trash existing list
534
535                TiXmlElement* pWindowNode=hRoot.FirstChild( "Windows" ).FirstChild().Element();
536                for( pWindowNode; pWindowNode; pWindowNode=pWindowNode-&gt;NextSiblingElement())
537                {
538                        WindowSettings w;
539                        const char *pName=pWindowNode-&gt;Attribute("name");
540                        if (pName) w.name=pName;
541                       
542                        pWindowNode-&gt;QueryIntAttribute("x", &amp;w.x); // If this fails, original value is left as-is
543                        pWindowNode-&gt;QueryIntAttribute("y", &amp;w.y);
544                        pWindowNode-&gt;QueryIntAttribute("w", &amp;w.w);
545                        pWindowNode-&gt;QueryIntAttribute("hh", &amp;w.h);
546
547                        m_windows.push_back(w);
548                }
549        }
550
551        // block: connection
552        {
553                pElem=hRoot.FirstChild("Connection").Element();
554                if (pElem)
555                {
556                        m_connection.ip=pElem-&gt;Attribute("ip");
557                        pElem-&gt;QueryDoubleAttribute("timeout",&amp;m_connection.timeout);
558                }
559        }
560}
561</pre></div><p>
562<h1>Full listing for dump_to_stdout </h1>
563<p>
564Below 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>
565<div class="fragment"><pre class="fragment">// tutorial demo program
566#include "stdafx.h"
567#include "tinyxml.h"
568
569// ----------------------------------------------------------------------
570// STDOUT dump and indenting utility functions
571// ----------------------------------------------------------------------
572const unsigned int NUM_INDENTS_PER_SPACE=2;
573
574const char * getIndent( unsigned int numIndents )
575{
576        static const char * pINDENT="                                      + ";
577        static const unsigned int LENGTH=strlen( pINDENT );
578        unsigned int n=numIndents*NUM_INDENTS_PER_SPACE;
579        if ( n &gt; LENGTH ) n = LENGTH;
580
581        return &amp;pINDENT[ LENGTH-n ];
582}
583
584// same as getIndent but no "+" at the end
585const char * getIndentAlt( unsigned int numIndents )
586{
587        static const char * pINDENT="                                        ";
588        static const unsigned int LENGTH=strlen( pINDENT );
589        unsigned int n=numIndents*NUM_INDENTS_PER_SPACE;
590        if ( n &gt; LENGTH ) n = LENGTH;
591
592        return &amp;pINDENT[ LENGTH-n ];
593}
594
595int dump_attribs_to_stdout(TiXmlElement* pElement, unsigned int indent)
596{
597        if ( !pElement ) return 0;
598
599        TiXmlAttribute* pAttrib=pElement-&gt;FirstAttribute();
600        int i=0;
601        int ival;
602        double dval;
603        const char* pIndent=getIndent(indent);
604        printf("\n");
605        while (pAttrib)
606        {
607                printf( "%s%s: value=[%s]", pIndent, pAttrib-&gt;Name(), pAttrib-&gt;Value());
608
609                if (pAttrib-&gt;QueryIntValue(&amp;ival)==TIXML_SUCCESS)    printf( " int=%d", ival);
610                if (pAttrib-&gt;QueryDoubleValue(&amp;dval)==TIXML_SUCCESS) printf( " d=%1.1f", dval);
611                printf( "\n" );
612                i++;
613                pAttrib=pAttrib-&gt;Next();
614        }
615        return i;       
616}
617
618void dump_to_stdout( TiXmlNode* pParent, unsigned int indent = 0 )
619{
620        if ( !pParent ) return;
621
622        TiXmlNode* pChild;
623        TiXmlText* pText;
624        int t = pParent-&gt;Type();
625        printf( "%s", getIndent(indent));
626        int num;
627
628        switch ( t )
629        {
630        case TiXmlNode::DOCUMENT:
631                printf( "Document" );
632                break;
633
634        case TiXmlNode::ELEMENT:
635                printf( "Element [%s]", pParent-&gt;Value() );
636                num=dump_attribs_to_stdout(pParent-&gt;ToElement(), indent+1);
637                switch(num)
638                {
639                        case 0:  printf( " (No attributes)"); break;
640                        case 1:  printf( "%s1 attribute", getIndentAlt(indent)); break;
641                        default: printf( "%s%d attributes", getIndentAlt(indent), num); break;
642                }
643                break;
644
645        case TiXmlNode::COMMENT:
646                printf( "Comment: [%s]", pParent-&gt;Value());
647                break;
648
649        case TiXmlNode::UNKNOWN:
650                printf( "Unknown" );
651                break;
652
653        case TiXmlNode::TEXT:
654                pText = pParent-&gt;ToText();
655                printf( "Text: [%s]", pText-&gt;Value() );
656                break;
657
658        case TiXmlNode::DECLARATION:
659                printf( "Declaration" );
660                break;
661        default:
662                break;
663        }
664        printf( "\n" );
665        for ( pChild = pParent-&gt;FirstChild(); pChild != 0; pChild = pChild-&gt;NextSibling())
666        {
667                dump_to_stdout( pChild, indent+1 );
668        }
669}
670
671// load the named file and dump its structure to STDOUT
672void dump_to_stdout(const char* pFilename)
673{
674        TiXmlDocument doc(pFilename);
675        bool loadOkay = doc.LoadFile();
676        if (loadOkay)
677        {
678                printf("\n%s:\n", pFilename);
679                dump_to_stdout( &amp;doc ); // defined later in the tutorial
680        }
681        else
682        {
683                printf("Failed to load file \"%s\"\n", pFilename);
684        }
685}
686
687// ----------------------------------------------------------------------
688// main() for printing files named on the command line
689// ----------------------------------------------------------------------
690int main(int argc, char* argv[])
691{
692        for (int i=1; i&lt;argc; i++)
693        {
694                dump_to_stdout(argv[i]);
695        }
696        return 0;
697}
698</pre></div><p>
699Run this from the command line or a DOS window, e.g.:<p>
700<div class="fragment"><pre class="fragment">C:\dev\tinyxml&gt; Debug\tinyxml_1.exe example1.xml
701
702example1.xml:
703Document
704+ Declaration
705+ Element [Hello]
706 (No attributes)
707  + Text: [World]
708</pre></div><p>
709<em> Authors and Changes <ul>
710<li>
711Written by Ellers, April, May, June 2005  </li>
712<li>
713Minor edits and integration into doc system, Lee Thomason September 2005  </li>
714<li>
715Updated by Ellers, October 2005  </li>
716</ul>
717</em> <hr size="1"><address style="align: right;"><small>Generated on Tue Sep 19 19:04:34 2006 for TinyXml by&nbsp;
718<a href="http://www.doxygen.org/index.html">
719<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.4.7 </small></address>
720</body>
721</html>
Note: See TracBrowser for help on using the repository browser.