1159b3361Sopenharmony_ci#include "tinyxml.h"
2159b3361Sopenharmony_ci#include <iostream>
3159b3361Sopenharmony_ci#include <sstream>
4159b3361Sopenharmony_ci#include <strstream>
5159b3361Sopenharmony_ciusing namespace std;
6159b3361Sopenharmony_ci
7159b3361Sopenharmony_ciint gPass = 0;
8159b3361Sopenharmony_ciint gFail = 0;
9159b3361Sopenharmony_ci
10159b3361Sopenharmony_ci// Utility functions:
11159b3361Sopenharmony_citemplate< class T >
12159b3361Sopenharmony_cibool XmlTest( const char* testString, T expected, T found, bool noEcho = false )
13159b3361Sopenharmony_ci{
14159b3361Sopenharmony_ci	if ( expected == found )
15159b3361Sopenharmony_ci		cout << "[pass]";
16159b3361Sopenharmony_ci	else
17159b3361Sopenharmony_ci		cout << "[fail]";
18159b3361Sopenharmony_ci
19159b3361Sopenharmony_ci	if ( noEcho )
20159b3361Sopenharmony_ci		cout << " " << testString;
21159b3361Sopenharmony_ci	else
22159b3361Sopenharmony_ci		cout << " " << testString << " [" << expected << "][" <<  found << "]";
23159b3361Sopenharmony_ci	cout << "\n";
24159b3361Sopenharmony_ci
25159b3361Sopenharmony_ci	bool pass = ( expected == found );
26159b3361Sopenharmony_ci	if ( pass )
27159b3361Sopenharmony_ci		++gPass;
28159b3361Sopenharmony_ci	else
29159b3361Sopenharmony_ci		++gFail;
30159b3361Sopenharmony_ci	return pass;
31159b3361Sopenharmony_ci}
32159b3361Sopenharmony_ci
33159b3361Sopenharmony_ci
34159b3361Sopenharmony_ci//
35159b3361Sopenharmony_ci// This file demonstrates some basic functionality of TinyXml.
36159b3361Sopenharmony_ci// Note that the example is very contrived. It presumes you know
37159b3361Sopenharmony_ci// what is in the XML file. But it does test the basic operations,
38159b3361Sopenharmony_ci// and show how to add and remove nodes.
39159b3361Sopenharmony_ci//
40159b3361Sopenharmony_ci
41159b3361Sopenharmony_ciint main()
42159b3361Sopenharmony_ci{
43159b3361Sopenharmony_ci	//
44159b3361Sopenharmony_ci	// We start with the 'demoStart' todo list. Process it. And
45159b3361Sopenharmony_ci	// should hopefully end up with the todo list as illustrated.
46159b3361Sopenharmony_ci	//
47159b3361Sopenharmony_ci	const char* demoStart =
48159b3361Sopenharmony_ci		"<?xml version=\"1.0\"  standalone='no' >\n"
49159b3361Sopenharmony_ci		"<!-- Our to do list data -->"
50159b3361Sopenharmony_ci		"<ToDo>\n"
51159b3361Sopenharmony_ci			"<!-- Do I need a secure PDA? -->\n"
52159b3361Sopenharmony_ci			"<Item priority=\"1\" distance='close'> Go to the <bold>Toy store!</bold></Item>"
53159b3361Sopenharmony_ci			"<Item priority=\"2\" distance='none'> Do bills   </Item>"
54159b3361Sopenharmony_ci			"<Item priority=\"2\" distance='far &amp; back'> Look for Evil Dinosaurs! </Item>"
55159b3361Sopenharmony_ci		"</ToDo>";
56159b3361Sopenharmony_ci
57159b3361Sopenharmony_ci	/*	What the todo list should look like after processing.
58159b3361Sopenharmony_ci		In stream (no formatting) representation. */
59159b3361Sopenharmony_ci	const char* demoEnd =
60159b3361Sopenharmony_ci		"<?xml version=\"1.0\" standalone=\"no\" ?>"
61159b3361Sopenharmony_ci		"<!-- Our to do list data -->"
62159b3361Sopenharmony_ci		"<ToDo>"
63159b3361Sopenharmony_ci			"<!-- Do I need a secure PDA? -->"
64159b3361Sopenharmony_ci		    "<Item priority=\"2\" distance=\"close\">Go to the"
65159b3361Sopenharmony_ci		        "<bold>Toy store!"
66159b3361Sopenharmony_ci		        "</bold>"
67159b3361Sopenharmony_ci		    "</Item>"
68159b3361Sopenharmony_ci		    "<Item priority=\"1\" distance=\"far\">Talk to:"
69159b3361Sopenharmony_ci		        "<Meeting where=\"School\">"
70159b3361Sopenharmony_ci		            "<Attendee name=\"Marple\" position=\"teacher\" />"
71159b3361Sopenharmony_ci		            "<Attendee name=\"Vo&#x82;\" position=\"counselor\" />"
72159b3361Sopenharmony_ci		        "</Meeting>"
73159b3361Sopenharmony_ci		        "<Meeting where=\"Lunch\" />"
74159b3361Sopenharmony_ci		    "</Item>"
75159b3361Sopenharmony_ci		    "<Item priority=\"2\" distance=\"here\">Do bills"
76159b3361Sopenharmony_ci		    "</Item>"
77159b3361Sopenharmony_ci		"</ToDo>";
78159b3361Sopenharmony_ci
79159b3361Sopenharmony_ci	// The example parses from the character string (above):
80159b3361Sopenharmony_ci
81159b3361Sopenharmony_ci	{
82159b3361Sopenharmony_ci		// Write to a file and read it back, to check file I/O.
83159b3361Sopenharmony_ci
84159b3361Sopenharmony_ci		TiXmlDocument doc( "demotest.xml" );
85159b3361Sopenharmony_ci		doc.Parse( demoStart );
86159b3361Sopenharmony_ci
87159b3361Sopenharmony_ci		if ( doc.Error() )
88159b3361Sopenharmony_ci		{
89159b3361Sopenharmony_ci			printf( "Error in %s: %s\n", doc.Value().c_str(), doc.ErrorDesc().c_str() );
90159b3361Sopenharmony_ci			exit( 1 );
91159b3361Sopenharmony_ci		}
92159b3361Sopenharmony_ci		doc.SaveFile();
93159b3361Sopenharmony_ci	}
94159b3361Sopenharmony_ci
95159b3361Sopenharmony_ci	TiXmlDocument doc( "demotest.xml" );
96159b3361Sopenharmony_ci	bool loadOkay = doc.LoadFile();
97159b3361Sopenharmony_ci
98159b3361Sopenharmony_ci	if ( !loadOkay )
99159b3361Sopenharmony_ci	{
100159b3361Sopenharmony_ci		printf( "Could not load test file 'demotest.xml'. Error='%s'. Exiting.\n", doc.ErrorDesc().c_str() );
101159b3361Sopenharmony_ci		exit( 1 );
102159b3361Sopenharmony_ci	}
103159b3361Sopenharmony_ci
104159b3361Sopenharmony_ci	printf( "** Demo doc read from disk: ** \n\n" );
105159b3361Sopenharmony_ci	doc.Print( stdout );
106159b3361Sopenharmony_ci
107159b3361Sopenharmony_ci	TiXmlNode* node = 0;
108159b3361Sopenharmony_ci	TiXmlElement* todoElement = 0;
109159b3361Sopenharmony_ci	TiXmlElement* itemElement = 0;
110159b3361Sopenharmony_ci
111159b3361Sopenharmony_ci
112159b3361Sopenharmony_ci	// --------------------------------------------------------
113159b3361Sopenharmony_ci	// An example of changing existing attributes, and removing
114159b3361Sopenharmony_ci	// an element from the document.
115159b3361Sopenharmony_ci	// --------------------------------------------------------
116159b3361Sopenharmony_ci
117159b3361Sopenharmony_ci	// Get the "ToDo" element.
118159b3361Sopenharmony_ci	// It is a child of the document, and can be selected by name.
119159b3361Sopenharmony_ci	node = doc.FirstChild( "ToDo" );
120159b3361Sopenharmony_ci	assert( node );
121159b3361Sopenharmony_ci	todoElement = node->ToElement();
122159b3361Sopenharmony_ci	assert( todoElement  );
123159b3361Sopenharmony_ci
124159b3361Sopenharmony_ci	// Going to the toy store is now our second priority...
125159b3361Sopenharmony_ci	// So set the "priority" attribute of the first item in the list.
126159b3361Sopenharmony_ci	node = todoElement->FirstChildElement();	// This skips the "PDA" comment.
127159b3361Sopenharmony_ci	assert( node );
128159b3361Sopenharmony_ci	itemElement = node->ToElement();
129159b3361Sopenharmony_ci	assert( itemElement  );
130159b3361Sopenharmony_ci	itemElement->SetAttribute( "priority", 2 );
131159b3361Sopenharmony_ci
132159b3361Sopenharmony_ci	// Change the distance to "doing bills" from
133159b3361Sopenharmony_ci	// "none" to "here". It's the next sibling element.
134159b3361Sopenharmony_ci	itemElement = itemElement->NextSiblingElement();
135159b3361Sopenharmony_ci	assert( itemElement );
136159b3361Sopenharmony_ci	itemElement->SetAttribute( "distance", "here" );
137159b3361Sopenharmony_ci
138159b3361Sopenharmony_ci	// Remove the "Look for Evil Dinosours!" item.
139159b3361Sopenharmony_ci	// It is 1 more sibling away. We ask the parent to remove
140159b3361Sopenharmony_ci	// a particular child.
141159b3361Sopenharmony_ci	itemElement = itemElement->NextSiblingElement();
142159b3361Sopenharmony_ci	todoElement->RemoveChild( itemElement );
143159b3361Sopenharmony_ci
144159b3361Sopenharmony_ci	itemElement = 0;
145159b3361Sopenharmony_ci
146159b3361Sopenharmony_ci	// --------------------------------------------------------
147159b3361Sopenharmony_ci	// What follows is an example of created elements and text
148159b3361Sopenharmony_ci	// nodes and adding them to the document.
149159b3361Sopenharmony_ci	// --------------------------------------------------------
150159b3361Sopenharmony_ci
151159b3361Sopenharmony_ci	// Add some meetings.
152159b3361Sopenharmony_ci	TiXmlElement item( "Item" );
153159b3361Sopenharmony_ci	item.SetAttribute( "priority", "1" );
154159b3361Sopenharmony_ci	item.SetAttribute( "distance", "far" );
155159b3361Sopenharmony_ci
156159b3361Sopenharmony_ci	TiXmlText text( "Talk to:" );
157159b3361Sopenharmony_ci
158159b3361Sopenharmony_ci	TiXmlElement meeting1( "Meeting" );
159159b3361Sopenharmony_ci	meeting1.SetAttribute( "where", "School" );
160159b3361Sopenharmony_ci
161159b3361Sopenharmony_ci	TiXmlElement meeting2( "Meeting" );
162159b3361Sopenharmony_ci	meeting2.SetAttribute( "where", "Lunch" );
163159b3361Sopenharmony_ci
164159b3361Sopenharmony_ci	TiXmlElement attendee1( "Attendee" );
165159b3361Sopenharmony_ci	attendee1.SetAttribute( "name", "Marple" );
166159b3361Sopenharmony_ci	attendee1.SetAttribute( "position", "teacher" );
167159b3361Sopenharmony_ci
168159b3361Sopenharmony_ci	TiXmlElement attendee2( "Attendee" );
169159b3361Sopenharmony_ci	attendee2.SetAttribute( "name", "Vo&#x82;" );
170159b3361Sopenharmony_ci	attendee2.SetAttribute( "position", "counselor" );
171159b3361Sopenharmony_ci
172159b3361Sopenharmony_ci	// Assemble the nodes we've created:
173159b3361Sopenharmony_ci	meeting1.InsertEndChild( attendee1 );
174159b3361Sopenharmony_ci	meeting1.InsertEndChild( attendee2 );
175159b3361Sopenharmony_ci
176159b3361Sopenharmony_ci	item.InsertEndChild( text );
177159b3361Sopenharmony_ci	item.InsertEndChild( meeting1 );
178159b3361Sopenharmony_ci	item.InsertEndChild( meeting2 );
179159b3361Sopenharmony_ci
180159b3361Sopenharmony_ci	// And add the node to the existing list after the first child.
181159b3361Sopenharmony_ci	node = todoElement->FirstChild( "Item" );
182159b3361Sopenharmony_ci	assert( node );
183159b3361Sopenharmony_ci	itemElement = node->ToElement();
184159b3361Sopenharmony_ci	assert( itemElement );
185159b3361Sopenharmony_ci
186159b3361Sopenharmony_ci	todoElement->InsertAfterChild( itemElement, item );
187159b3361Sopenharmony_ci
188159b3361Sopenharmony_ci	printf( "\n** Demo doc processed: ** \n\n" );
189159b3361Sopenharmony_ci	doc.Print( stdout );
190159b3361Sopenharmony_ci
191159b3361Sopenharmony_ci	printf( "** Demo doc processed to stream: ** \n\n" );
192159b3361Sopenharmony_ci	cout << doc << endl << endl;
193159b3361Sopenharmony_ci
194159b3361Sopenharmony_ci	// --------------------------------------------------------
195159b3361Sopenharmony_ci	// Different tests...do we have what we expect?
196159b3361Sopenharmony_ci	// --------------------------------------------------------
197159b3361Sopenharmony_ci
198159b3361Sopenharmony_ci	int count = 0;
199159b3361Sopenharmony_ci	TiXmlElement*	element;
200159b3361Sopenharmony_ci
201159b3361Sopenharmony_ci	//////////////////////////////////////////////////////
202159b3361Sopenharmony_ci	cout << "** Basic structure. **\n";
203159b3361Sopenharmony_ci	ostringstream outputStream( ostringstream::out );
204159b3361Sopenharmony_ci	outputStream << doc;
205159b3361Sopenharmony_ci
206159b3361Sopenharmony_ci	XmlTest( "Output stream correct.", string( demoEnd ), outputStream.str(), true );
207159b3361Sopenharmony_ci
208159b3361Sopenharmony_ci	node = doc.RootElement();
209159b3361Sopenharmony_ci	XmlTest( "Root element exists.", true, ( node != 0 && node->ToElement() ) );
210159b3361Sopenharmony_ci	XmlTest( "Root element value is 'ToDo'.", string( "ToDo" ), node->Value() );
211159b3361Sopenharmony_ci	node = node->FirstChild();
212159b3361Sopenharmony_ci	XmlTest( "First child exists & is a comment.", true, ( node != 0 && node->ToComment() ) );
213159b3361Sopenharmony_ci	node = node->NextSibling();
214159b3361Sopenharmony_ci	XmlTest( "Sibling element exists & is an element.", true, ( node != 0 && node->ToElement() ) );
215159b3361Sopenharmony_ci	XmlTest( "Value is 'Item'.", string( "Item" ), node->Value() );
216159b3361Sopenharmony_ci	node = node->FirstChild();
217159b3361Sopenharmony_ci	XmlTest( "First child exists.", true, ( node != 0 && node->ToText() ) );
218159b3361Sopenharmony_ci	XmlTest( "Value is 'Go to the'.", string( "Go to the" ), node->Value() );
219159b3361Sopenharmony_ci
220159b3361Sopenharmony_ci
221159b3361Sopenharmony_ci	//////////////////////////////////////////////////////
222159b3361Sopenharmony_ci	cout << "\n** Iterators. **" << "\n";
223159b3361Sopenharmony_ci	// Walk all the top level nodes of the document.
224159b3361Sopenharmony_ci	count = 0;
225159b3361Sopenharmony_ci	for( node = doc.FirstChild();
226159b3361Sopenharmony_ci		 node;
227159b3361Sopenharmony_ci		 node = node->NextSibling() )
228159b3361Sopenharmony_ci	{
229159b3361Sopenharmony_ci		count++;
230159b3361Sopenharmony_ci	}
231159b3361Sopenharmony_ci	XmlTest( "Top level nodes, using First / Next.", 3, count );
232159b3361Sopenharmony_ci
233159b3361Sopenharmony_ci	count = 0;
234159b3361Sopenharmony_ci	for( node = doc.LastChild();
235159b3361Sopenharmony_ci		 node;
236159b3361Sopenharmony_ci		 node = node->PreviousSibling() )
237159b3361Sopenharmony_ci	{
238159b3361Sopenharmony_ci		count++;
239159b3361Sopenharmony_ci	}
240159b3361Sopenharmony_ci	XmlTest( "Top level nodes, using Last / Previous.", 3, count );
241159b3361Sopenharmony_ci
242159b3361Sopenharmony_ci	// Walk all the top level nodes of the document,
243159b3361Sopenharmony_ci	// using a different sytax.
244159b3361Sopenharmony_ci	count = 0;
245159b3361Sopenharmony_ci	for( node = doc.IterateChildren( 0 );
246159b3361Sopenharmony_ci		 node;
247159b3361Sopenharmony_ci		 node = doc.IterateChildren( node ) )
248159b3361Sopenharmony_ci	{
249159b3361Sopenharmony_ci		count++;
250159b3361Sopenharmony_ci	}
251159b3361Sopenharmony_ci	XmlTest( "Top level nodes, using IterateChildren.", 3, count );
252159b3361Sopenharmony_ci
253159b3361Sopenharmony_ci	// Walk all the elements in a node.
254159b3361Sopenharmony_ci	count = 0;
255159b3361Sopenharmony_ci	for( element = todoElement->FirstChildElement();
256159b3361Sopenharmony_ci		 element;
257159b3361Sopenharmony_ci		 element = element->NextSiblingElement() )
258159b3361Sopenharmony_ci	{
259159b3361Sopenharmony_ci		count++;
260159b3361Sopenharmony_ci	}
261159b3361Sopenharmony_ci	XmlTest( "Children of the 'ToDo' element, using First / Next.",
262159b3361Sopenharmony_ci			 3, count );
263159b3361Sopenharmony_ci
264159b3361Sopenharmony_ci	// Walk all the elements in a node by value.
265159b3361Sopenharmony_ci	count = 0;
266159b3361Sopenharmony_ci	for( node = todoElement->FirstChild( "Item" );
267159b3361Sopenharmony_ci		 node;
268159b3361Sopenharmony_ci		 node = node->NextSibling( "Item" ) )
269159b3361Sopenharmony_ci	{
270159b3361Sopenharmony_ci		count++;
271159b3361Sopenharmony_ci	}
272159b3361Sopenharmony_ci	XmlTest( "'Item' children of the 'ToDo' element, using First/Next.", 3, count );
273159b3361Sopenharmony_ci
274159b3361Sopenharmony_ci	count = 0;
275159b3361Sopenharmony_ci	for( node = todoElement->LastChild( "Item" );
276159b3361Sopenharmony_ci		 node;
277159b3361Sopenharmony_ci		 node = node->PreviousSibling( "Item" ) )
278159b3361Sopenharmony_ci	{
279159b3361Sopenharmony_ci		count++;
280159b3361Sopenharmony_ci	}
281159b3361Sopenharmony_ci	XmlTest( "'Item' children of the 'ToDo' element, using Last/Previous.", 3, count );
282159b3361Sopenharmony_ci
283159b3361Sopenharmony_ci
284159b3361Sopenharmony_ci	//////////////////////////////////////////////////////
285159b3361Sopenharmony_ci	cout << "\n** Parsing. **\n";
286159b3361Sopenharmony_ci	istringstream parse0( "<Element0 attribute0='foo0' attribute1= noquotes attribute2 = '&gt;' />" );
287159b3361Sopenharmony_ci	TiXmlElement element0( "default" );
288159b3361Sopenharmony_ci	parse0 >> element0;
289159b3361Sopenharmony_ci
290159b3361Sopenharmony_ci	XmlTest( "Element parsed, value is 'Element0'.", string( "Element0" ), element0.Value() );
291159b3361Sopenharmony_ci	XmlTest( "Reads attribute 'attribute0=\"foo0\"'.", string( "foo0" ), *( element0.Attribute( "attribute0" ) ) );
292159b3361Sopenharmony_ci	XmlTest( "Reads incorrectly formatted 'attribute1=noquotes'.", string( "noquotes" ), *( element0.Attribute( "attribute1" ) ) );
293159b3361Sopenharmony_ci	XmlTest( "Read attribute with entity value '>'.", string( ">" ), *( element0.Attribute( "attribute2" ) ) );
294159b3361Sopenharmony_ci
295159b3361Sopenharmony_ci	//////////////////////////////////////////////////////
296159b3361Sopenharmony_ci	cout << "\n** Streaming. **\n";
297159b3361Sopenharmony_ci
298159b3361Sopenharmony_ci	// Round trip check: stream in, then stream back out to verify. The stream
299159b3361Sopenharmony_ci	// out has already been checked, above. We use the output
300159b3361Sopenharmony_ci
301159b3361Sopenharmony_ci	istringstream inputStringStream( outputStream.str() );
302159b3361Sopenharmony_ci	TiXmlDocument document0;
303159b3361Sopenharmony_ci
304159b3361Sopenharmony_ci	inputStringStream >> document0;
305159b3361Sopenharmony_ci
306159b3361Sopenharmony_ci	ostringstream outputStream0( ostringstream::out );
307159b3361Sopenharmony_ci	outputStream0 << document0;
308159b3361Sopenharmony_ci
309159b3361Sopenharmony_ci	XmlTest( "Stream round trip correct.", string( demoEnd ), outputStream0.str(), true );
310159b3361Sopenharmony_ci
311159b3361Sopenharmony_ci	//////////////////////////////////////////////////////
312159b3361Sopenharmony_ci	cout << "\n** Parsing, no Condense Whitespace **\n";
313159b3361Sopenharmony_ci	TiXmlBase::SetCondenseWhiteSpace( false );
314159b3361Sopenharmony_ci
315159b3361Sopenharmony_ci	istringstream parse1( "<start>This  is    \ntext</start>" );
316159b3361Sopenharmony_ci	TiXmlElement text1( "text" );
317159b3361Sopenharmony_ci	parse1 >> text1;
318159b3361Sopenharmony_ci
319159b3361Sopenharmony_ci	XmlTest( "Condense white space OFF.", string( "This  is    \ntext" ),
320159b3361Sopenharmony_ci										  text1.FirstChild()->Value(),
321159b3361Sopenharmony_ci										  true );
322159b3361Sopenharmony_ci
323159b3361Sopenharmony_ci	cout << endl << "Pass " << gPass << ", Fail " << gFail << endl;
324159b3361Sopenharmony_ci	return 0;
325159b3361Sopenharmony_ci}
326159b3361Sopenharmony_ci
327