1 #include "tinyxml.h"
2 #include <iostream>
3 #include <sstream>
4 #include <strstream>
5 using namespace std;
6
7 int gPass = 0;
8 int gFail = 0;
9
10 // Utility functions:
11 template< class T >
XmlTest(const char * testString,T expected,T found,bool noEcho=false)12 bool XmlTest( const char* testString, T expected, T found, bool noEcho = false )
13 {
14 if ( expected == found )
15 cout << "[pass]";
16 else
17 cout << "[fail]";
18
19 if ( noEcho )
20 cout << " " << testString;
21 else
22 cout << " " << testString << " [" << expected << "][" << found << "]";
23 cout << "\n";
24
25 bool pass = ( expected == found );
26 if ( pass )
27 ++gPass;
28 else
29 ++gFail;
30 return pass;
31 }
32
33
34 //
35 // This file demonstrates some basic functionality of TinyXml.
36 // Note that the example is very contrived. It presumes you know
37 // what is in the XML file. But it does test the basic operations,
38 // and show how to add and remove nodes.
39 //
40
main()41 int main()
42 {
43 //
44 // We start with the 'demoStart' todo list. Process it. And
45 // should hopefully end up with the todo list as illustrated.
46 //
47 const char* demoStart =
48 "<?xml version=\"1.0\" standalone='no' >\n"
49 "<!-- Our to do list data -->"
50 "<ToDo>\n"
51 "<!-- Do I need a secure PDA? -->\n"
52 "<Item priority=\"1\" distance='close'> Go to the <bold>Toy store!</bold></Item>"
53 "<Item priority=\"2\" distance='none'> Do bills </Item>"
54 "<Item priority=\"2\" distance='far & back'> Look for Evil Dinosaurs! </Item>"
55 "</ToDo>";
56
57 /* What the todo list should look like after processing.
58 In stream (no formatting) representation. */
59 const char* demoEnd =
60 "<?xml version=\"1.0\" standalone=\"no\" ?>"
61 "<!-- Our to do list data -->"
62 "<ToDo>"
63 "<!-- Do I need a secure PDA? -->"
64 "<Item priority=\"2\" distance=\"close\">Go to the"
65 "<bold>Toy store!"
66 "</bold>"
67 "</Item>"
68 "<Item priority=\"1\" distance=\"far\">Talk to:"
69 "<Meeting where=\"School\">"
70 "<Attendee name=\"Marple\" position=\"teacher\" />"
71 "<Attendee name=\"Vo‚\" position=\"counselor\" />"
72 "</Meeting>"
73 "<Meeting where=\"Lunch\" />"
74 "</Item>"
75 "<Item priority=\"2\" distance=\"here\">Do bills"
76 "</Item>"
77 "</ToDo>";
78
79 // The example parses from the character string (above):
80
81 {
82 // Write to a file and read it back, to check file I/O.
83
84 TiXmlDocument doc( "demotest.xml" );
85 doc.Parse( demoStart );
86
87 if ( doc.Error() )
88 {
89 printf( "Error in %s: %s\n", doc.Value().c_str(), doc.ErrorDesc().c_str() );
90 exit( 1 );
91 }
92 doc.SaveFile();
93 }
94
95 TiXmlDocument doc( "demotest.xml" );
96 bool loadOkay = doc.LoadFile();
97
98 if ( !loadOkay )
99 {
100 printf( "Could not load test file 'demotest.xml'. Error='%s'. Exiting.\n", doc.ErrorDesc().c_str() );
101 exit( 1 );
102 }
103
104 printf( "** Demo doc read from disk: ** \n\n" );
105 doc.Print( stdout );
106
107 TiXmlNode* node = 0;
108 TiXmlElement* todoElement = 0;
109 TiXmlElement* itemElement = 0;
110
111
112 // --------------------------------------------------------
113 // An example of changing existing attributes, and removing
114 // an element from the document.
115 // --------------------------------------------------------
116
117 // Get the "ToDo" element.
118 // It is a child of the document, and can be selected by name.
119 node = doc.FirstChild( "ToDo" );
120 assert( node );
121 todoElement = node->ToElement();
122 assert( todoElement );
123
124 // Going to the toy store is now our second priority...
125 // So set the "priority" attribute of the first item in the list.
126 node = todoElement->FirstChildElement(); // This skips the "PDA" comment.
127 assert( node );
128 itemElement = node->ToElement();
129 assert( itemElement );
130 itemElement->SetAttribute( "priority", 2 );
131
132 // Change the distance to "doing bills" from
133 // "none" to "here". It's the next sibling element.
134 itemElement = itemElement->NextSiblingElement();
135 assert( itemElement );
136 itemElement->SetAttribute( "distance", "here" );
137
138 // Remove the "Look for Evil Dinosours!" item.
139 // It is 1 more sibling away. We ask the parent to remove
140 // a particular child.
141 itemElement = itemElement->NextSiblingElement();
142 todoElement->RemoveChild( itemElement );
143
144 itemElement = 0;
145
146 // --------------------------------------------------------
147 // What follows is an example of created elements and text
148 // nodes and adding them to the document.
149 // --------------------------------------------------------
150
151 // Add some meetings.
152 TiXmlElement item( "Item" );
153 item.SetAttribute( "priority", "1" );
154 item.SetAttribute( "distance", "far" );
155
156 TiXmlText text( "Talk to:" );
157
158 TiXmlElement meeting1( "Meeting" );
159 meeting1.SetAttribute( "where", "School" );
160
161 TiXmlElement meeting2( "Meeting" );
162 meeting2.SetAttribute( "where", "Lunch" );
163
164 TiXmlElement attendee1( "Attendee" );
165 attendee1.SetAttribute( "name", "Marple" );
166 attendee1.SetAttribute( "position", "teacher" );
167
168 TiXmlElement attendee2( "Attendee" );
169 attendee2.SetAttribute( "name", "Vo‚" );
170 attendee2.SetAttribute( "position", "counselor" );
171
172 // Assemble the nodes we've created:
173 meeting1.InsertEndChild( attendee1 );
174 meeting1.InsertEndChild( attendee2 );
175
176 item.InsertEndChild( text );
177 item.InsertEndChild( meeting1 );
178 item.InsertEndChild( meeting2 );
179
180 // And add the node to the existing list after the first child.
181 node = todoElement->FirstChild( "Item" );
182 assert( node );
183 itemElement = node->ToElement();
184 assert( itemElement );
185
186 todoElement->InsertAfterChild( itemElement, item );
187
188 printf( "\n** Demo doc processed: ** \n\n" );
189 doc.Print( stdout );
190
191 printf( "** Demo doc processed to stream: ** \n\n" );
192 cout << doc << endl << endl;
193
194 // --------------------------------------------------------
195 // Different tests...do we have what we expect?
196 // --------------------------------------------------------
197
198 int count = 0;
199 TiXmlElement* element;
200
201 //////////////////////////////////////////////////////
202 cout << "** Basic structure. **\n";
203 ostringstream outputStream( ostringstream::out );
204 outputStream << doc;
205
206 XmlTest( "Output stream correct.", string( demoEnd ), outputStream.str(), true );
207
208 node = doc.RootElement();
209 XmlTest( "Root element exists.", true, ( node != 0 && node->ToElement() ) );
210 XmlTest( "Root element value is 'ToDo'.", string( "ToDo" ), node->Value() );
211 node = node->FirstChild();
212 XmlTest( "First child exists & is a comment.", true, ( node != 0 && node->ToComment() ) );
213 node = node->NextSibling();
214 XmlTest( "Sibling element exists & is an element.", true, ( node != 0 && node->ToElement() ) );
215 XmlTest( "Value is 'Item'.", string( "Item" ), node->Value() );
216 node = node->FirstChild();
217 XmlTest( "First child exists.", true, ( node != 0 && node->ToText() ) );
218 XmlTest( "Value is 'Go to the'.", string( "Go to the" ), node->Value() );
219
220
221 //////////////////////////////////////////////////////
222 cout << "\n** Iterators. **" << "\n";
223 // Walk all the top level nodes of the document.
224 count = 0;
225 for( node = doc.FirstChild();
226 node;
227 node = node->NextSibling() )
228 {
229 count++;
230 }
231 XmlTest( "Top level nodes, using First / Next.", 3, count );
232
233 count = 0;
234 for( node = doc.LastChild();
235 node;
236 node = node->PreviousSibling() )
237 {
238 count++;
239 }
240 XmlTest( "Top level nodes, using Last / Previous.", 3, count );
241
242 // Walk all the top level nodes of the document,
243 // using a different sytax.
244 count = 0;
245 for( node = doc.IterateChildren( 0 );
246 node;
247 node = doc.IterateChildren( node ) )
248 {
249 count++;
250 }
251 XmlTest( "Top level nodes, using IterateChildren.", 3, count );
252
253 // Walk all the elements in a node.
254 count = 0;
255 for( element = todoElement->FirstChildElement();
256 element;
257 element = element->NextSiblingElement() )
258 {
259 count++;
260 }
261 XmlTest( "Children of the 'ToDo' element, using First / Next.",
262 3, count );
263
264 // Walk all the elements in a node by value.
265 count = 0;
266 for( node = todoElement->FirstChild( "Item" );
267 node;
268 node = node->NextSibling( "Item" ) )
269 {
270 count++;
271 }
272 XmlTest( "'Item' children of the 'ToDo' element, using First/Next.", 3, count );
273
274 count = 0;
275 for( node = todoElement->LastChild( "Item" );
276 node;
277 node = node->PreviousSibling( "Item" ) )
278 {
279 count++;
280 }
281 XmlTest( "'Item' children of the 'ToDo' element, using Last/Previous.", 3, count );
282
283
284 //////////////////////////////////////////////////////
285 cout << "\n** Parsing. **\n";
286 istringstream parse0( "<Element0 attribute0='foo0' attribute1= noquotes attribute2 = '>' />" );
287 TiXmlElement element0( "default" );
288 parse0 >> element0;
289
290 XmlTest( "Element parsed, value is 'Element0'.", string( "Element0" ), element0.Value() );
291 XmlTest( "Reads attribute 'attribute0=\"foo0\"'.", string( "foo0" ), *( element0.Attribute( "attribute0" ) ) );
292 XmlTest( "Reads incorrectly formatted 'attribute1=noquotes'.", string( "noquotes" ), *( element0.Attribute( "attribute1" ) ) );
293 XmlTest( "Read attribute with entity value '>'.", string( ">" ), *( element0.Attribute( "attribute2" ) ) );
294
295 //////////////////////////////////////////////////////
296 cout << "\n** Streaming. **\n";
297
298 // Round trip check: stream in, then stream back out to verify. The stream
299 // out has already been checked, above. We use the output
300
301 istringstream inputStringStream( outputStream.str() );
302 TiXmlDocument document0;
303
304 inputStringStream >> document0;
305
306 ostringstream outputStream0( ostringstream::out );
307 outputStream0 << document0;
308
309 XmlTest( "Stream round trip correct.", string( demoEnd ), outputStream0.str(), true );
310
311 //////////////////////////////////////////////////////
312 cout << "\n** Parsing, no Condense Whitespace **\n";
313 TiXmlBase::SetCondenseWhiteSpace( false );
314
315 istringstream parse1( "<start>This is \ntext</start>" );
316 TiXmlElement text1( "text" );
317 parse1 >> text1;
318
319 XmlTest( "Condense white space OFF.", string( "This is \ntext" ),
320 text1.FirstChild()->Value(),
321 true );
322
323 cout << endl << "Pass " << gPass << ", Fail " << gFail << endl;
324 return 0;
325 }
326
327