327 lines
9.6 KiB
C++
327 lines
9.6 KiB
C++
#include "tinyxml.h"
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <strstream>
|
|
using namespace std;
|
|
|
|
int gPass = 0;
|
|
int gFail = 0;
|
|
|
|
// Utility functions:
|
|
template< class T >
|
|
bool XmlTest( const char* testString, T expected, T found, bool noEcho = false )
|
|
{
|
|
if ( expected == found )
|
|
cout << "[pass]";
|
|
else
|
|
cout << "[fail]";
|
|
|
|
if ( noEcho )
|
|
cout << " " << testString;
|
|
else
|
|
cout << " " << testString << " [" << expected << "][" << found << "]";
|
|
cout << "\n";
|
|
|
|
bool pass = ( expected == found );
|
|
if ( pass )
|
|
++gPass;
|
|
else
|
|
++gFail;
|
|
return pass;
|
|
}
|
|
|
|
|
|
//
|
|
// This file demonstrates some basic functionality of TinyXml.
|
|
// Note that the example is very contrived. It presumes you know
|
|
// what is in the XML file. But it does test the basic operations,
|
|
// and show how to add and remove nodes.
|
|
//
|
|
|
|
int main()
|
|
{
|
|
//
|
|
// We start with the 'demoStart' todo list. Process it. And
|
|
// should hopefully end up with the todo list as illustrated.
|
|
//
|
|
const char* demoStart =
|
|
"<?xml version=\"1.0\" standalone='no' >\n"
|
|
"<!-- Our to do list data -->"
|
|
"<ToDo>\n"
|
|
"<!-- Do I need a secure PDA? -->\n"
|
|
"<Item priority=\"1\" distance='close'> Go to the <bold>Toy store!</bold></Item>"
|
|
"<Item priority=\"2\" distance='none'> Do bills </Item>"
|
|
"<Item priority=\"2\" distance='far & back'> Look for Evil Dinosaurs! </Item>"
|
|
"</ToDo>";
|
|
|
|
/* What the todo list should look like after processing.
|
|
In stream (no formatting) representation. */
|
|
const char* demoEnd =
|
|
"<?xml version=\"1.0\" standalone=\"no\" ?>"
|
|
"<!-- Our to do list data -->"
|
|
"<ToDo>"
|
|
"<!-- Do I need a secure PDA? -->"
|
|
"<Item priority=\"2\" distance=\"close\">Go to the"
|
|
"<bold>Toy store!"
|
|
"</bold>"
|
|
"</Item>"
|
|
"<Item priority=\"1\" distance=\"far\">Talk to:"
|
|
"<Meeting where=\"School\">"
|
|
"<Attendee name=\"Marple\" position=\"teacher\" />"
|
|
"<Attendee name=\"Vo‚\" position=\"counselor\" />"
|
|
"</Meeting>"
|
|
"<Meeting where=\"Lunch\" />"
|
|
"</Item>"
|
|
"<Item priority=\"2\" distance=\"here\">Do bills"
|
|
"</Item>"
|
|
"</ToDo>";
|
|
|
|
// The example parses from the character string (above):
|
|
|
|
{
|
|
// Write to a file and read it back, to check file I/O.
|
|
|
|
TiXmlDocument doc( "demotest.xml" );
|
|
doc.Parse( demoStart );
|
|
|
|
if ( doc.Error() )
|
|
{
|
|
printf( "Error in %s: %s\n", doc.Value().c_str(), doc.ErrorDesc().c_str() );
|
|
exit( 1 );
|
|
}
|
|
doc.SaveFile();
|
|
}
|
|
|
|
TiXmlDocument doc( "demotest.xml" );
|
|
bool loadOkay = doc.LoadFile();
|
|
|
|
if ( !loadOkay )
|
|
{
|
|
printf( "Could not load test file 'demotest.xml'. Error='%s'. Exiting.\n", doc.ErrorDesc().c_str() );
|
|
exit( 1 );
|
|
}
|
|
|
|
printf( "** Demo doc read from disk: ** \n\n" );
|
|
doc.Print( stdout );
|
|
|
|
TiXmlNode* node = 0;
|
|
TiXmlElement* todoElement = 0;
|
|
TiXmlElement* itemElement = 0;
|
|
|
|
|
|
// --------------------------------------------------------
|
|
// An example of changing existing attributes, and removing
|
|
// an element from the document.
|
|
// --------------------------------------------------------
|
|
|
|
// Get the "ToDo" element.
|
|
// It is a child of the document, and can be selected by name.
|
|
node = doc.FirstChild( "ToDo" );
|
|
assert( node );
|
|
todoElement = node->ToElement();
|
|
assert( todoElement );
|
|
|
|
// Going to the toy store is now our second priority...
|
|
// So set the "priority" attribute of the first item in the list.
|
|
node = todoElement->FirstChildElement(); // This skips the "PDA" comment.
|
|
assert( node );
|
|
itemElement = node->ToElement();
|
|
assert( itemElement );
|
|
itemElement->SetAttribute( "priority", 2 );
|
|
|
|
// Change the distance to "doing bills" from
|
|
// "none" to "here". It's the next sibling element.
|
|
itemElement = itemElement->NextSiblingElement();
|
|
assert( itemElement );
|
|
itemElement->SetAttribute( "distance", "here" );
|
|
|
|
// Remove the "Look for Evil Dinosours!" item.
|
|
// It is 1 more sibling away. We ask the parent to remove
|
|
// a particular child.
|
|
itemElement = itemElement->NextSiblingElement();
|
|
todoElement->RemoveChild( itemElement );
|
|
|
|
itemElement = 0;
|
|
|
|
// --------------------------------------------------------
|
|
// What follows is an example of created elements and text
|
|
// nodes and adding them to the document.
|
|
// --------------------------------------------------------
|
|
|
|
// Add some meetings.
|
|
TiXmlElement item( "Item" );
|
|
item.SetAttribute( "priority", "1" );
|
|
item.SetAttribute( "distance", "far" );
|
|
|
|
TiXmlText text( "Talk to:" );
|
|
|
|
TiXmlElement meeting1( "Meeting" );
|
|
meeting1.SetAttribute( "where", "School" );
|
|
|
|
TiXmlElement meeting2( "Meeting" );
|
|
meeting2.SetAttribute( "where", "Lunch" );
|
|
|
|
TiXmlElement attendee1( "Attendee" );
|
|
attendee1.SetAttribute( "name", "Marple" );
|
|
attendee1.SetAttribute( "position", "teacher" );
|
|
|
|
TiXmlElement attendee2( "Attendee" );
|
|
attendee2.SetAttribute( "name", "Vo‚" );
|
|
attendee2.SetAttribute( "position", "counselor" );
|
|
|
|
// Assemble the nodes we've created:
|
|
meeting1.InsertEndChild( attendee1 );
|
|
meeting1.InsertEndChild( attendee2 );
|
|
|
|
item.InsertEndChild( text );
|
|
item.InsertEndChild( meeting1 );
|
|
item.InsertEndChild( meeting2 );
|
|
|
|
// And add the node to the existing list after the first child.
|
|
node = todoElement->FirstChild( "Item" );
|
|
assert( node );
|
|
itemElement = node->ToElement();
|
|
assert( itemElement );
|
|
|
|
todoElement->InsertAfterChild( itemElement, item );
|
|
|
|
printf( "\n** Demo doc processed: ** \n\n" );
|
|
doc.Print( stdout );
|
|
|
|
printf( "** Demo doc processed to stream: ** \n\n" );
|
|
cout << doc << endl << endl;
|
|
|
|
// --------------------------------------------------------
|
|
// Different tests...do we have what we expect?
|
|
// --------------------------------------------------------
|
|
|
|
int count = 0;
|
|
TiXmlElement* element;
|
|
|
|
//////////////////////////////////////////////////////
|
|
cout << "** Basic structure. **\n";
|
|
ostringstream outputStream( ostringstream::out );
|
|
outputStream << doc;
|
|
|
|
XmlTest( "Output stream correct.", string( demoEnd ), outputStream.str(), true );
|
|
|
|
node = doc.RootElement();
|
|
XmlTest( "Root element exists.", true, ( node != 0 && node->ToElement() ) );
|
|
XmlTest( "Root element value is 'ToDo'.", string( "ToDo" ), node->Value() );
|
|
node = node->FirstChild();
|
|
XmlTest( "First child exists & is a comment.", true, ( node != 0 && node->ToComment() ) );
|
|
node = node->NextSibling();
|
|
XmlTest( "Sibling element exists & is an element.", true, ( node != 0 && node->ToElement() ) );
|
|
XmlTest( "Value is 'Item'.", string( "Item" ), node->Value() );
|
|
node = node->FirstChild();
|
|
XmlTest( "First child exists.", true, ( node != 0 && node->ToText() ) );
|
|
XmlTest( "Value is 'Go to the'.", string( "Go to the" ), node->Value() );
|
|
|
|
|
|
//////////////////////////////////////////////////////
|
|
cout << "\n** Iterators. **" << "\n";
|
|
// Walk all the top level nodes of the document.
|
|
count = 0;
|
|
for( node = doc.FirstChild();
|
|
node;
|
|
node = node->NextSibling() )
|
|
{
|
|
count++;
|
|
}
|
|
XmlTest( "Top level nodes, using First / Next.", 3, count );
|
|
|
|
count = 0;
|
|
for( node = doc.LastChild();
|
|
node;
|
|
node = node->PreviousSibling() )
|
|
{
|
|
count++;
|
|
}
|
|
XmlTest( "Top level nodes, using Last / Previous.", 3, count );
|
|
|
|
// Walk all the top level nodes of the document,
|
|
// using a different sytax.
|
|
count = 0;
|
|
for( node = doc.IterateChildren( 0 );
|
|
node;
|
|
node = doc.IterateChildren( node ) )
|
|
{
|
|
count++;
|
|
}
|
|
XmlTest( "Top level nodes, using IterateChildren.", 3, count );
|
|
|
|
// Walk all the elements in a node.
|
|
count = 0;
|
|
for( element = todoElement->FirstChildElement();
|
|
element;
|
|
element = element->NextSiblingElement() )
|
|
{
|
|
count++;
|
|
}
|
|
XmlTest( "Children of the 'ToDo' element, using First / Next.",
|
|
3, count );
|
|
|
|
// Walk all the elements in a node by value.
|
|
count = 0;
|
|
for( node = todoElement->FirstChild( "Item" );
|
|
node;
|
|
node = node->NextSibling( "Item" ) )
|
|
{
|
|
count++;
|
|
}
|
|
XmlTest( "'Item' children of the 'ToDo' element, using First/Next.", 3, count );
|
|
|
|
count = 0;
|
|
for( node = todoElement->LastChild( "Item" );
|
|
node;
|
|
node = node->PreviousSibling( "Item" ) )
|
|
{
|
|
count++;
|
|
}
|
|
XmlTest( "'Item' children of the 'ToDo' element, using Last/Previous.", 3, count );
|
|
|
|
|
|
//////////////////////////////////////////////////////
|
|
cout << "\n** Parsing. **\n";
|
|
istringstream parse0( "<Element0 attribute0='foo0' attribute1= noquotes attribute2 = '>' />" );
|
|
TiXmlElement element0( "default" );
|
|
parse0 >> element0;
|
|
|
|
XmlTest( "Element parsed, value is 'Element0'.", string( "Element0" ), element0.Value() );
|
|
XmlTest( "Reads attribute 'attribute0=\"foo0\"'.", string( "foo0" ), *( element0.Attribute( "attribute0" ) ) );
|
|
XmlTest( "Reads incorrectly formatted 'attribute1=noquotes'.", string( "noquotes" ), *( element0.Attribute( "attribute1" ) ) );
|
|
XmlTest( "Read attribute with entity value '>'.", string( ">" ), *( element0.Attribute( "attribute2" ) ) );
|
|
|
|
//////////////////////////////////////////////////////
|
|
cout << "\n** Streaming. **\n";
|
|
|
|
// Round trip check: stream in, then stream back out to verify. The stream
|
|
// out has already been checked, above. We use the output
|
|
|
|
istringstream inputStringStream( outputStream.str() );
|
|
TiXmlDocument document0;
|
|
|
|
inputStringStream >> document0;
|
|
|
|
ostringstream outputStream0( ostringstream::out );
|
|
outputStream0 << document0;
|
|
|
|
XmlTest( "Stream round trip correct.", string( demoEnd ), outputStream0.str(), true );
|
|
|
|
//////////////////////////////////////////////////////
|
|
cout << "\n** Parsing, no Condense Whitespace **\n";
|
|
TiXmlBase::SetCondenseWhiteSpace( false );
|
|
|
|
istringstream parse1( "<start>This is \ntext</start>" );
|
|
TiXmlElement text1( "text" );
|
|
parse1 >> text1;
|
|
|
|
XmlTest( "Condense white space OFF.", string( "This is \ntext" ),
|
|
text1.FirstChild()->Value(),
|
|
true );
|
|
|
|
cout << endl << "Pass " << gPass << ", Fail " << gFail << endl;
|
|
return 0;
|
|
}
|
|
|