1#include "tinyxml.h" 2#include <iostream> 3#include <sstream> 4#include <strstream> 5using namespace std; 6 7int gPass = 0; 8int gFail = 0; 9 10// Utility functions: 11template< class T > 12bool 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 41int 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