TinyXml HOWTO

Author: Andrew Ellerton
Date: April 2004

Preliminary

This page contains a bunch of examples of using TinyXml.

Each demo is written in a standalone function. If you want to try the code, all you need to do is copy/paste the code into a file, then have a main to call it.

So if the example has a function:

void write_simple_doc()
{
    ...
}

then the complete program you need to try it is:

#include "stdafx.h" // <-- you MIGHT need this
#include "tinyxml.h" // <-- you definitely need this ;)

void write_simple_doc()
{
    ...
}

void main( void )
{
    write_simple_doc();
}

Two example XML datasets/files will be used. The first looks like this:

<?xml version="1.0" ?>
<Hello>World</Hello>

The other:

<?xml version="1.0" ?>
<poetry>
<!-- my great work of art -->
<verse>
<?xml version="1.0" ?>
<poetry>
<!-- my great work of art -->
<verse>
Alas
  Great Whatever
    Alas (again)
</verse>
</poetry>

Getting Started

Load XML from a file

Loading a file is as simple as:

void load_file( )
{
    TiXmlDocument doc( "demo.xml" );
    bool loadOkay = doc.LoadFile();

    if ( loadOkay )
    {
        // Your document is loaded - do what you like
        // with it.
        //
        // Here we'll dump the structure to STDOUT,
        // just for example
        dump_to_stdout( &doc );
    }
    else
    {
        // load failed
    }
}

The dump_to_stdout function is defined in the section Dump structure of a Document to STDOUT below. If you run this program with this XML:

<?xml version="1.0" ?>
<Hello>World</Hello>

You'll see this:

DOCUMENT
+ DECLARATION
+ ELEMENT Hello
  + TEXT[World]

Building Documents Pragmatically

Example:

void write_simple_doc( )
{
    // Make xml: <?xml ..><Hello>World</Hello>
    TiXmlDocument doc;
    TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );
    TiXmlElement * element = new TiXmlElement( "Hello" );
    TiXmlText * text = new TiXmlText( "World" );
    element->LinkEndChild( text );
    doc.LinkEndChild( decl );
    doc.LinkEndChild( element );
    
    dump_to_stdout( &doc );
    doc.SaveFile( "madeByHand.xml" );
}

Alternatively:

void write_simple_doc2( )
{
    // same as write_simple_doc1 but add each node
    // as early as possible into the tree.

    TiXmlDocument doc;
    TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );
    doc.LinkEndChild( decl );
    
    TiXmlElement * element = new TiXmlElement( "Hello" );
    doc.LinkEndChild( element );
    
    TiXmlText * text = new TiXmlText( "World" );
    element->LinkEndChild( text );
    
    dump_to_stdout( &doc );
    doc.SaveFile( "madeByHand2.xml" );
}

Both of these produce the same XML, namely:

<?xml version="1.0" ?>
<Hello>World</Hello>

Or in structure form:

DOCUMENT
+ DECLARATION
+ ELEMENT Hello
  + TEXT[World]

Saving Documents to File

This function:

void write_simple_doc3( )  
{  
    // This example courtesy of polocolege
 
    TiXmlDocument doc;  
    TiXmlDeclaration * decl = new TiXmlDeclaration( "1.0", "", "" );  
    doc.LinkEndChild( decl );  
 
    TiXmlElement * element = new TiXmlElement( "Hello" );  
    doc.LinkEndChild( element );  
 
    TiXmlText * text = new TiXmlText( "Opening a new salutation" );  
    element->LinkEndChild( text );  
 
    TiXmlElement * element2 = new TiXmlElement( "Greeting" );  
    element->LinkEndChild( element2 );  
 
    TiXmlText * text2 = new TiXmlText( "How are you?" );  
    element2->LinkEndChild( text2 );  
 
    TiXmlElement * element3 = new TiXmlElement( "Language" );  
    element2->LinkEndChild( element3 );  
 
    TiXmlText * text3 = new TiXmlText( "English" );  
    element3->LinkEndChild( text3 );  
 
    TiXmlElement * element4 = new TiXmlElement( "Exclamation" );  
    element->LinkEndChild( element4 );  
 
    TiXmlText * text4 = new TiXmlText( "You have children!" );  
    element4->LinkEndChild( text4 );  
 
    dump_to_stdout( &doc );
    doc.SaveFile( "madeByHand3.xml" );  
}  

Produces this structure:

Document
+ Declaration
+ Element "Hello"
  + Text: [Opening a new salutation]
  + Element "Greeting"
    + Text: [How are you?]
    + Element "Language"
      + Text: [English]
  + Element "Exclamation"
    + Text: [You have children!]

The file madeByHand3.xml looks exactly like this (including indents):

<?xml version="1.0" ?>
<Hello>Opening a new salutation
    <Greeting>How are you?
        <Language>English</Language>
    </Greeting>
    <Exclamation>You have children!</Exclamation>
</Hello>

I 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.

I haven't looked yet to see if there is a way to turn off indenting when writing a file - its bound to be easy.

Iterating Over Documents

Dump structure of a Document to STDOUT

Often when you're starting its helpful and reassuring to know that you're document got loaded as you expect it to.

Below I've defined a function to walk a document and write contents to STDOUT:

// a utility function defining a very simple method to indent a line of text
const char * getIndent( unsigned int numIndents )
{
    static const char * pINDENT = "                                      + ";
    static const unsigned int LENGTH = strlen( pINDENT );

    if ( numIndents > LENGTH ) numIndents = LENGTH;

    return &pINDENT[ LENGTH-numIndents ];
}

void dump_to_stdout( TiXmlNode * pParent, unsigned int indent = 0 )
{
    if ( !pParent ) return;

    TiXmlText *pText;
    int t = pParent->Type();
    printf( "%s", getIndent( indent));

    switch ( t )
    {
    case TiXmlNode::DOCUMENT:
        printf( "Document" );
        break;

    case TiXmlNode::ELEMENT:
        printf( "Element \"%s\"", pParent->Value() );
        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" );

    TiXmlNode * pChild;

    for ( pChild = pParent->FirstChild(); pChild != 0; pChild = pChild->NextSibling()) 
    {
        dump_to_stdout( pChild, indent+2 );
    }
}

To load a file and dump its structure:

void load_and_display( )
{
    // important for the poetry demo, but you may not need this 
    // in your own projects
    TiXmlBase::SetCondenseWhiteSpace( false );

    TiXmlDocument doc( "demo.xml" );
    bool loadOkay = doc.LoadFile();

    if ( loadOkay )
    {
        dump_to_stdout( &doc );
    }
    else
    {
        printf( "Something went wrong\n" );
    }
}

If you run this with the first XML file you'll see this on STDOUT:

DOCUMENT
+ DECLARATION
+ ELEMENT Hello
  + TEXT[World]

and on the second XML file:

DOCUMENT
+ DECLARATION
+ ELEMENT poetry
  + COMMENT:  my great work of art
  + ELEMENT verse
    + TEXT[
Alas
  Great Whatever
    Alas (again)
]

Note that if you call dump_to_stdout like this:

dump_to_stdout( doc.RootElement());

You'll see this instead:

ELEMENT Hello
+ TEXT[World]

and:

ELEMENT poetry
+ COMMENT:  my great work of art
+ ELEMENT verse
+ TEXT[
Alas
  Great Whatever
    Alas (again)
] 

Todo

More to come later :)