blob: a573f94c46145ccdfeb3db20825e6064c0a11d3c [file] [log] [blame]
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001/*
2Original code by Lee Thomason (www.grinninglizard.com)
3
4This software is provided 'as-is', without any express or implied
5warranty. In no event will the authors be held liable for any
6damages arising from the use of this software.
7
8Permission is granted to anyone to use this software for any
9purpose, including commercial applications, and to alter it and
10redistribute it freely, subject to the following restrictions:
11
121. The origin of this software must not be misrepresented; you must
13not claim that you wrote the original software. If you use this
14software in a product, an acknowledgment in the product documentation
15would be appreciated but is not required.
16
172. Altered source versions must be plainly marked as such, and
18must not be misrepresented as being the original software.
19
203. This notice may not be removed or altered from any source
21distribution.
22*/
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -080023
Lee Thomason7d00b9a2012-02-27 17:54:22 -080024#ifndef TINYXML2_INCLUDED
U-Lama\Leee13c3e62011-12-28 14:36:55 -080025#define TINYXML2_INCLUDED
26
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -070027#ifdef ANDROID_NDK
28 #include <ctype.h>
29 #include <limits.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <stdarg.h>
34#else
35 #include <cctype>
36 #include <climits>
37 #include <cstdio>
38 #include <cstdlib>
39 #include <cstring>
40 #include <cstdarg>
41#endif
Lee Thomason (grinliz)6a22be22012-04-04 12:39:05 -070042
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -070043/*
Lee Thomason7d00b9a2012-02-27 17:54:22 -080044 TODO: intern strings instead of allocation.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080045*/
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -080046/*
47 gcc: g++ -Wall tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
48*/
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -080049
U-Lama\Lee4cee6112011-12-31 14:58:18 -080050#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
51 #ifndef DEBUG
52 #define DEBUG
53 #endif
54#endif
55
56
57#if defined(DEBUG)
58 #if defined(_MSC_VER)
Guillermo A. Amaral68b0c872012-03-24 11:07:19 -070059 #define TIXMLASSERT( x ) if ( !(x)) { __debugbreak(); } //if ( !(x)) WinDebugBreak()
U-Lama\Lee4cee6112011-12-31 14:58:18 -080060 #elif defined (ANDROID_NDK)
61 #include <android/log.h>
62 #define TIXMLASSERT( x ) if ( !(x)) { __android_log_assert( "assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__ ); }
63 #else
64 #include <assert.h>
65 #define TIXMLASSERT assert
66 #endif
67#else
68 #define TIXMLASSERT( x ) {}
69#endif
70
U-Lama\Leee13c3e62011-12-28 14:36:55 -080071
Lee Thomason1a1d4a72012-02-15 09:09:25 -080072#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
73 // Microsoft visual studio, version 2005 and higher.
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -070074 /*int _snprintf_s(
75 char *buffer,
76 size_t sizeOfBuffer,
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -070077 size_t count,
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -070078 const char *format [,
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -070079 argument] ...
Lee Thomason (grinliz)598c13e2012-04-06 21:18:23 -070080 );*/
81 inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... ) {
82 va_list va;
83 va_start( va, format );
84 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
85 va_end( va );
86 return result;
87 }
Lee Thomason1a1d4a72012-02-15 09:09:25 -080088 #define TIXML_SSCANF sscanf_s
Lee Thomason (grinliz)b9e791f2012-04-06 21:27:10 -070089#else
U-Stream\Leeae25a442012-02-17 17:48:16 -080090 // GCC version 3 and higher
Lee Thomason1a1d4a72012-02-15 09:09:25 -080091 //#warning( "Using sn* functions." )
92 #define TIXML_SNPRINTF snprintf
93 #define TIXML_SSCANF sscanf
Lee Thomason1a1d4a72012-02-15 09:09:25 -080094#endif
Lee Thomason1ff38e02012-02-14 18:18:16 -080095
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -070096static const int TIXML2_MAJOR_VERSION = 1;
97static const int TIXML2_MINOR_VERSION = 0;
Lee Thomason (grinliz)4dbe8692012-09-08 21:23:33 -070098static const int TIXML2_PATCH_VERSION = 7;
Lee Thomason1ff38e02012-02-14 18:18:16 -080099
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800100namespace tinyxml2
101{
Lee Thomasonce0763e2012-01-11 15:43:54 -0800102class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800103class XMLElement;
104class XMLAttribute;
105class XMLComment;
106class XMLNode;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800107class XMLText;
Lee Thomason50f97b22012-02-11 16:33:40 -0800108class XMLDeclaration;
109class XMLUnknown;
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800110
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800111class XMLPrinter;
Lee Thomason5cae8972012-01-24 18:03:07 -0800112
U-Stream\Leeae25a442012-02-17 17:48:16 -0800113/*
114 A class that wraps strings. Normally stores the start and end
115 pointers into the XML file itself, and will apply normalization
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800116 and entity translation if actually read. Can also store (and memory
U-Stream\Leeae25a442012-02-17 17:48:16 -0800117 manage) a traditional char[]
118*/
Lee Thomason39ede242012-01-20 11:27:56 -0800119class StrPair
120{
Lee Thomasond34f52c2012-01-20 12:55:24 -0800121public:
Lee Thomason39ede242012-01-20 11:27:56 -0800122 enum {
Lee Thomasone4422302012-01-20 17:59:50 -0800123 NEEDS_ENTITY_PROCESSING = 0x01,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800124 NEEDS_NEWLINE_NORMALIZATION = 0x02,
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700125 COLLAPSE_WHITESPACE = 0x04,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800126
127 TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason6f381b72012-03-02 12:59:39 -0800128 TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason18d68bd2012-01-26 18:17:26 -0800129 ATTRIBUTE_NAME = 0,
130 ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
Lee Thomason6f381b72012-03-02 12:59:39 -0800131 ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700132 COMMENT = NEEDS_NEWLINE_NORMALIZATION
Lee Thomason39ede242012-01-20 11:27:56 -0800133 };
134
135 StrPair() : flags( 0 ), start( 0 ), end( 0 ) {}
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800136 ~StrPair();
137
Lee Thomason5ce89412012-03-20 13:23:44 -0700138 void Set( char* _start, char* _end, int _flags ) {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800139 Reset();
Lee Thomason5ce89412012-03-20 13:23:44 -0700140 this->start = _start; this->end = _end; this->flags = _flags | NEEDS_FLUSH;
Lee Thomason39ede242012-01-20 11:27:56 -0800141 }
142 const char* GetStr();
Lee Thomasone4422302012-01-20 17:59:50 -0800143 bool Empty() const { return start == end; }
Lee Thomason39ede242012-01-20 11:27:56 -0800144
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700145 void SetInternedStr( const char* str ) { Reset(); this->start = const_cast<char*>(str); }
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800146 void SetStr( const char* str, int flags=0 );
147
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700148 char* ParseText( char* in, const char* endTag, int strFlags );
Lee Thomason56bdd022012-02-09 18:16:58 -0800149 char* ParseName( char* in );
150
Lee Thomason2c85a712012-01-31 08:24:24 -0800151
Lee Thomason39ede242012-01-20 11:27:56 -0800152private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800153 void Reset();
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700154 void CollapseWhitespace();
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800155
Lee Thomasone4422302012-01-20 17:59:50 -0800156 enum {
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800157 NEEDS_FLUSH = 0x100,
158 NEEDS_DELETE = 0x200
Lee Thomasone4422302012-01-20 17:59:50 -0800159 };
160
Lee Thomason39ede242012-01-20 11:27:56 -0800161 // After parsing, if *end != 0, it can be set to zero.
162 int flags;
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700163 char* start;
Lee Thomason39ede242012-01-20 11:27:56 -0800164 char* end;
165};
166
U-Lama\Lee560bd472011-12-28 19:42:49 -0800167
U-Stream\Leeae25a442012-02-17 17:48:16 -0800168/*
169 A dynamic array of Plain Old Data. Doesn't support constructors, etc.
170 Has a small initial memory pool, so that low or no usage will not
171 cause a call to new/delete
172*/
Lee Thomason2c85a712012-01-31 08:24:24 -0800173template <class T, int INIT>
174class DynArray
175{
176public:
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700177 DynArray< T, INIT >()
Lee Thomason2c85a712012-01-31 08:24:24 -0800178 {
179 mem = pool;
180 allocated = INIT;
181 size = 0;
182 }
183 ~DynArray()
184 {
185 if ( mem != pool ) {
Lee Thomasona2ae54e2012-05-18 13:47:48 -0700186 delete [] mem;
Lee Thomason2c85a712012-01-31 08:24:24 -0800187 }
188 }
189 void Push( T t )
190 {
191 EnsureCapacity( size+1 );
192 mem[size++] = t;
193 }
194
195 T* PushArr( int count )
196 {
197 EnsureCapacity( size+count );
198 T* ret = &mem[size];
199 size += count;
200 return ret;
201 }
202 T Pop() {
203 return mem[--size];
204 }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700205 void PopArr( int count )
Lee Thomason2c85a712012-01-31 08:24:24 -0800206 {
207 TIXMLASSERT( size >= count );
208 size -= count;
209 }
210
U-Stream\Leeae25a442012-02-17 17:48:16 -0800211 bool Empty() const { return size == 0; }
212 T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
213 const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
214 int Size() const { return size; }
215 int Capacity() const { return allocated; }
216 const T* Mem() const { return mem; }
217 T* Mem() { return mem; }
Lee Thomason2c85a712012-01-31 08:24:24 -0800218
219
220private:
221 void EnsureCapacity( int cap ) {
222 if ( cap > allocated ) {
223 int newAllocated = cap * 2;
224 T* newMem = new T[newAllocated];
225 memcpy( newMem, mem, sizeof(T)*size ); // warning: not using constructors, only works for PODs
226 if ( mem != pool ) delete [] mem;
227 mem = newMem;
228 allocated = newAllocated;
229 }
230 }
231
232 T* mem;
233 T pool[INIT];
234 int allocated; // objects allocated
235 int size; // number objects in use
236};
237
Lee Thomason50adb4c2012-02-13 15:07:09 -0800238
U-Stream\Leeae25a442012-02-17 17:48:16 -0800239/*
Thomas Roß08bdf502012-05-12 14:21:23 +0200240 Parent virtual class of a pool for fast allocation
U-Stream\Leeae25a442012-02-17 17:48:16 -0800241 and deallocation of objects.
242*/
Lee Thomasond1983222012-02-06 08:41:24 -0800243class MemPool
244{
245public:
246 MemPool() {}
247 virtual ~MemPool() {}
248
249 virtual int ItemSize() const = 0;
250 virtual void* Alloc() = 0;
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700251 virtual void Free( void* ) = 0;
Lee Thomasond1983222012-02-06 08:41:24 -0800252};
253
Lee Thomason50adb4c2012-02-13 15:07:09 -0800254
U-Stream\Leeae25a442012-02-17 17:48:16 -0800255/*
256 Template child class to create pools of the correct type.
257*/
Lee Thomasond1983222012-02-06 08:41:24 -0800258template< int SIZE >
259class MemPoolT : public MemPool
260{
261public:
Lee Thomason455c9d42012-02-06 09:14:14 -0800262 MemPoolT() : root(0), currentAllocs(0), nAllocs(0), maxAllocs(0) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800263 ~MemPoolT() {
264 // Delete the blocks.
265 for( int i=0; i<blockPtrs.Size(); ++i ) {
266 delete blockPtrs[i];
267 }
268 }
269
270 virtual int ItemSize() const { return SIZE; }
Lee Thomason455c9d42012-02-06 09:14:14 -0800271 int CurrentAllocs() const { return currentAllocs; }
Lee Thomasond1983222012-02-06 08:41:24 -0800272
273 virtual void* Alloc() {
274 if ( !root ) {
275 // Need a new block.
276 Block* block = new Block();
277 blockPtrs.Push( block );
278
279 for( int i=0; i<COUNT-1; ++i ) {
280 block->chunk[i].next = &block->chunk[i+1];
281 }
282 block->chunk[COUNT-1].next = 0;
283 root = block->chunk;
284 }
285 void* result = root;
286 root = root->next;
Lee Thomason455c9d42012-02-06 09:14:14 -0800287
288 ++currentAllocs;
289 if ( currentAllocs > maxAllocs ) maxAllocs = currentAllocs;
290 nAllocs++;
Lee Thomasond1983222012-02-06 08:41:24 -0800291 return result;
292 }
293 virtual void Free( void* mem ) {
294 if ( !mem ) return;
Lee Thomason455c9d42012-02-06 09:14:14 -0800295 --currentAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800296 Chunk* chunk = (Chunk*)mem;
Lee Thomason (grinliz)6020a012012-09-08 21:15:09 -0700297#ifdef DEBUG
Lee Thomasond1983222012-02-06 08:41:24 -0800298 memset( chunk, 0xfe, sizeof(Chunk) );
Lee Thomason (grinliz)6020a012012-09-08 21:15:09 -0700299#endif
Lee Thomasond1983222012-02-06 08:41:24 -0800300 chunk->next = root;
301 root = chunk;
302 }
Lee Thomason455c9d42012-02-06 09:14:14 -0800303 void Trace( const char* name ) {
Lee Thomason43f59302012-02-06 18:18:11 -0800304 printf( "Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
305 name, maxAllocs, maxAllocs*SIZE/1024, currentAllocs, SIZE, nAllocs, blockPtrs.Size() );
Lee Thomason455c9d42012-02-06 09:14:14 -0800306 }
Lee Thomasond1983222012-02-06 08:41:24 -0800307
308private:
309 enum { COUNT = 1024/SIZE };
310 union Chunk {
311 Chunk* next;
312 char mem[SIZE];
313 };
314 struct Block {
315 Chunk chunk[COUNT];
316 };
317 DynArray< Block*, 10 > blockPtrs;
318 Chunk* root;
Lee Thomason455c9d42012-02-06 09:14:14 -0800319
320 int currentAllocs;
321 int nAllocs;
322 int maxAllocs;
Lee Thomasond1983222012-02-06 08:41:24 -0800323};
324
Lee Thomason2c85a712012-01-31 08:24:24 -0800325
Lee Thomason56bdd022012-02-09 18:16:58 -0800326
327/**
328 Implements the interface to the "Visitor pattern" (see the Accept() method.)
329 If you call the Accept() method, it requires being passed a XMLVisitor
330 class to handle callbacks. For nodes that contain other nodes (Document, Element)
Thomas Roß08bdf502012-05-12 14:21:23 +0200331 you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs
Lee Thomason56bdd022012-02-09 18:16:58 -0800332 are simply called with Visit().
333
334 If you return 'true' from a Visit method, recursive parsing will continue. If you return
Thomas Roß08bdf502012-05-12 14:21:23 +0200335 false, <b>no children of this node or its sibilings</b> will be visited.
Lee Thomason56bdd022012-02-09 18:16:58 -0800336
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700337 All flavors of Visit methods have a default implementation that returns 'true' (continue
Lee Thomason56bdd022012-02-09 18:16:58 -0800338 visiting). You need to only override methods that are interesting to you.
339
Thomas Roß08bdf502012-05-12 14:21:23 +0200340 Generally Accept() is called on the TiXmlDocument, although all nodes support visiting.
Lee Thomason56bdd022012-02-09 18:16:58 -0800341
342 You should never change the document from a callback.
343
344 @sa XMLNode::Accept()
345*/
346class XMLVisitor
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800347{
348public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800349 virtual ~XMLVisitor() {}
Lee Thomasond1983222012-02-06 08:41:24 -0800350
Lee Thomason56bdd022012-02-09 18:16:58 -0800351 /// Visit a document.
352 virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { return true; }
353 /// Visit a document.
354 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
355
356 /// Visit an element.
357 virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { return true; }
358 /// Visit an element.
359 virtual bool VisitExit( const XMLElement& /*element*/ ) { return true; }
360
Thomas Roß08bdf502012-05-12 14:21:23 +0200361 /// Visit a declaration.
Lee Thomason50f97b22012-02-11 16:33:40 -0800362 virtual bool Visit( const XMLDeclaration& /*declaration*/ ) { return true; }
Thomas Roß08bdf502012-05-12 14:21:23 +0200363 /// Visit a text node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800364 virtual bool Visit( const XMLText& /*text*/ ) { return true; }
Thomas Roß08bdf502012-05-12 14:21:23 +0200365 /// Visit a comment node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800366 virtual bool Visit( const XMLComment& /*comment*/ ) { return true; }
Thomas Roß08bdf502012-05-12 14:21:23 +0200367 /// Visit an unknown node.
Lee Thomason50f97b22012-02-11 16:33:40 -0800368 virtual bool Visit( const XMLUnknown& /*unknown*/ ) { return true; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800369};
370
371
U-Stream\Leeae25a442012-02-17 17:48:16 -0800372/*
373 Utility functionality.
374*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800375class XMLUtil
376{
Lee Thomasond1983222012-02-06 08:41:24 -0800377public:
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700378 // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
Lee Thomason56bdd022012-02-09 18:16:58 -0800379 // correct, but simple, and usually works.
Lee Thomason (grinliz)390e9782012-07-01 21:22:53 -0700380 static const char* SkipWhiteSpace( const char* p ) { while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast<const unsigned char*>(p) ) ) { ++p; } return p; }
381 static char* SkipWhiteSpace( char* p ) { while( !IsUTF8Continuation(*p) && isspace( *reinterpret_cast<unsigned char*>(p) ) ) { ++p; } return p; }
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -0700382 static bool IsWhiteSpace( char p ) { return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) ); }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800383
384 inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
385 int n = 0;
Lee Thomasond34f52c2012-01-20 12:55:24 -0800386 if ( p == q ) {
387 return true;
388 }
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800389 while( *p && *q && *p == *q && n<nChar ) {
390 ++p; ++q; ++n;
391 }
392 if ( (n == nChar) || ( *p == 0 && *q == 0 ) ) {
393 return true;
394 }
395 return false;
396 }
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -0700397 inline static int IsUTF8Continuation( const char p ) { return p & 0x80; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800398 inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalnum( anyByte ) : 1; }
399 inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalpha( anyByte ) : 1; }
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800400
401 static const char* ReadBOM( const char* p, bool* hasBOM );
402 // p is the starting location,
403 // the UTF-8 value of the entity will be placed in value, and length filled in.
Lee Thomasond6277762012-02-22 16:00:12 -0800404 static const char* GetCharacterRef( const char* p, char* value, int* length );
405 static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
Lee Thomason21be8822012-07-15 17:27:22 -0700406
407 // converts primitive types to strings
408 static void ToStr( int v, char* buffer, int bufferSize );
409 static void ToStr( unsigned v, char* buffer, int bufferSize );
410 static void ToStr( bool v, char* buffer, int bufferSize );
411 static void ToStr( float v, char* buffer, int bufferSize );
412 static void ToStr( double v, char* buffer, int bufferSize );
413
414 // converts strings to primitive types
415 static bool ToInt( const char* str, int* value );
416 static bool ToUnsigned( const char* str, unsigned* value );
417 static bool ToBool( const char* str, bool* value );
418 static bool ToFloat( const char* str, float* value );
419 static bool ToDouble( const char* str, double* value );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800420};
421
Lee Thomason5cae8972012-01-24 18:03:07 -0800422
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800423/** XMLNode is a base class for every object that is in the
424 XML Document Object Model (DOM), except XMLAttributes.
425 Nodes have siblings, a parent, and children which can
426 be navigated. A node is always in a XMLDocument.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700427 The type of a XMLNode can be queried, and it can
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800428 be cast to its more defined type.
429
Thomas Roß08bdf502012-05-12 14:21:23 +0200430 A XMLDocument allocates memory for all its Nodes.
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800431 When the XMLDocument gets deleted, all its Nodes
432 will also be deleted.
433
434 @verbatim
435 A Document can contain: Element (container or leaf)
436 Comment (leaf)
437 Unknown (leaf)
438 Declaration( leaf )
439
440 An Element can contain: Element (container or leaf)
441 Text (leaf)
442 Attributes (not on tree)
443 Comment (leaf)
444 Unknown (leaf)
445
446 @endverbatim
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800447*/
Lee Thomasond1983222012-02-06 08:41:24 -0800448class XMLNode
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800449{
450 friend class XMLDocument;
451 friend class XMLElement;
452public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800453
454 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason751da522012-02-10 08:50:51 -0800455 const XMLDocument* GetDocument() const { return document; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800456 /// Get the XMLDocument that owns this XMLNode.
Lee Thomason56bdd022012-02-09 18:16:58 -0800457 XMLDocument* GetDocument() { return document; }
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800458
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800459 virtual XMLElement* ToElement() { return 0; } ///< Safely cast to an Element, or null.
460 virtual XMLText* ToText() { return 0; } ///< Safely cast to Text, or null.
461 virtual XMLComment* ToComment() { return 0; } ///< Safely cast to a Comment, or null.
462 virtual XMLDocument* ToDocument() { return 0; } ///< Safely cast to a Document, or null.
463 virtual XMLDeclaration* ToDeclaration() { return 0; } ///< Safely cast to a Declaration, or null.
464 virtual XMLUnknown* ToUnknown() { return 0; } ///< Safely cast to an Unknown, or null.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800465
Lee Thomason50f97b22012-02-11 16:33:40 -0800466 virtual const XMLElement* ToElement() const { return 0; }
467 virtual const XMLText* ToText() const { return 0; }
468 virtual const XMLComment* ToComment() const { return 0; }
469 virtual const XMLDocument* ToDocument() const { return 0; }
470 virtual const XMLDeclaration* ToDeclaration() const { return 0; }
471 virtual const XMLUnknown* ToUnknown() const { return 0; }
Lee Thomason751da522012-02-10 08:50:51 -0800472
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800473 /** The meaning of 'value' changes for the specific type.
474 @verbatim
Thomas Roß08bdf502012-05-12 14:21:23 +0200475 Document: empty
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800476 Element: name of the element
477 Comment: the comment text
478 Unknown: the tag contents
479 Text: the text string
480 @endverbatim
481 */
Lee Thomason2c85a712012-01-31 08:24:24 -0800482 const char* Value() const { return value.GetStr(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800483 /** Set the Value of an XML node.
484 @sa Value()
485 */
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800486 void SetValue( const char* val, bool staticMem=false );
Lee Thomason2c85a712012-01-31 08:24:24 -0800487
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800488 /// Get the parent of this node on the DOM.
Lee Thomason751da522012-02-10 08:50:51 -0800489 const XMLNode* Parent() const { return parent; }
490 XMLNode* Parent() { return parent; }
491
Lee Thomason50f97b22012-02-11 16:33:40 -0800492 /// Returns true if this node has no children.
493 bool NoChildren() const { return !firstChild; }
Lee Thomason751da522012-02-10 08:50:51 -0800494
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800495 /// Get the first child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800496 const XMLNode* FirstChild() const { return firstChild; }
497 XMLNode* FirstChild() { return firstChild; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800498 /** Get the first child element, or optionally the first child
499 element with the specified name.
500 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800501 const XMLElement* FirstChildElement( const char* value=0 ) const;
Lee Thomason5ce89412012-03-20 13:23:44 -0700502 XMLElement* FirstChildElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( _value )); }
Lee Thomason3f57d272012-01-11 15:30:03 -0800503
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800504 /// Get the last child node, or null if none exists.
Lee Thomason56bdd022012-02-09 18:16:58 -0800505 const XMLNode* LastChild() const { return lastChild; }
506 XMLNode* LastChild() { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800507
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800508 /** Get the last child element or optionally the last child
509 element with the specified name.
510 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800511 const XMLElement* LastChildElement( const char* value=0 ) const;
Lee Thomason5ce89412012-03-20 13:23:44 -0700512 XMLElement* LastChildElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(_value) ); }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700513
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800514 /// Get the previous (left) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800515 const XMLNode* PreviousSibling() const { return prev; }
516 XMLNode* PreviousSibling() { return prev; }
517
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800518 /// Get the previous (left) sibling element of this node, with an opitionally supplied name.
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800519 const XMLElement* PreviousSiblingElement( const char* value=0 ) const ;
Lee Thomason5ce89412012-03-20 13:23:44 -0700520 XMLElement* PreviousSiblingElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( _value ) ); }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700521
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800522 /// Get the next (right) sibling node of this node.
Lee Thomason56bdd022012-02-09 18:16:58 -0800523 const XMLNode* NextSibling() const { return next; }
524 XMLNode* NextSibling() { return next; }
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700525
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800526 /// Get the next (right) sibling element of this node, with an opitionally supplied name.
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800527 const XMLElement* NextSiblingElement( const char* value=0 ) const;
Lee Thomason5ce89412012-03-20 13:23:44 -0700528 XMLElement* NextSiblingElement( const char* _value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( _value ) ); }
Lee Thomason56bdd022012-02-09 18:16:58 -0800529
Lee Thomason1ff38e02012-02-14 18:18:16 -0800530 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800531 Add a child node as the last (right) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800532 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800533 XMLNode* InsertEndChild( XMLNode* addThis );
Lee Thomason618dbf82012-02-28 12:34:27 -0800534
535 XMLNode* LinkEndChild( XMLNode* addThis ) { return InsertEndChild( addThis ); }
Lee Thomason1ff38e02012-02-14 18:18:16 -0800536 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800537 Add a child node as the first (left) child.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800538 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800539 XMLNode* InsertFirstChild( XMLNode* addThis );
Lee Thomason1ff38e02012-02-14 18:18:16 -0800540 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800541 Add a node after the specified child node.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800542 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800543 XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700544
U-Stream\Leeae25a442012-02-17 17:48:16 -0800545 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800546 Delete all the children of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800547 */
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800548 void DeleteChildren();
U-Stream\Leeae25a442012-02-17 17:48:16 -0800549
550 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800551 Delete a child of this node.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800552 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800553 void DeleteChild( XMLNode* node );
554
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800555 /**
556 Make a copy of this node, but not its children.
557 You may pass in a Document pointer that will be
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700558 the owner of the new Node. If the 'document' is
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800559 null, then the node returned will be allocated
560 from the current Document. (this->GetDocument())
561
562 Note: if called on a XMLDocument, this will return null.
563 */
564 virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
565
566 /**
567 Test if 2 nodes are the same, but don't test children.
568 The 2 nodes do not need to be in the same Document.
569
570 Note: if called on a XMLDocument, this will return false.
571 */
572 virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
573
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700574 /** Accept a hierarchical visit of the nodes in the TinyXML DOM. Every node in the
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800575 XML tree will be conditionally visited and the host will be called back
576 via the TiXmlVisitor interface.
577
578 This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
579 the XML for the callbacks, so the performance of TinyXML is unchanged by using this
580 interface versus any other.)
581
582 The interface has been based on ideas from:
583
584 - http://www.saxproject.org/
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700585 - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800586
587 Which are both good references for "visiting".
588
589 An example of using Accept():
590 @verbatim
591 TiXmlPrinter printer;
592 tinyxmlDoc.Accept( &printer );
593 const char* xmlcstr = printer.CStr();
594 @endverbatim
595 */
Lee Thomason56bdd022012-02-09 18:16:58 -0800596 virtual bool Accept( XMLVisitor* visitor ) const = 0;
Lee Thomason56bdd022012-02-09 18:16:58 -0800597
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800598 // internal
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800599 virtual char* ParseDeep( char*, StrPair* );
Lee Thomason3f57d272012-01-11 15:30:03 -0800600
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800601protected:
602 XMLNode( XMLDocument* );
Lee Thomasond1983222012-02-06 08:41:24 -0800603 virtual ~XMLNode();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800604 XMLNode( const XMLNode& ); // not supported
PKEuSc28ba3a2012-07-16 03:08:47 -0700605 XMLNode& operator=( const XMLNode& ); // not supported
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700606
Lee Thomason3f57d272012-01-11 15:30:03 -0800607 XMLDocument* document;
608 XMLNode* parent;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800609 mutable StrPair value;
Lee Thomason3f57d272012-01-11 15:30:03 -0800610
611 XMLNode* firstChild;
612 XMLNode* lastChild;
613
614 XMLNode* prev;
615 XMLNode* next;
616
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800617private:
Lee Thomasond1983222012-02-06 08:41:24 -0800618 MemPool* memPool;
Lee Thomason18d68bd2012-01-26 18:17:26 -0800619 void Unlink( XMLNode* child );
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800620};
621
622
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800623/** XML text.
624
625 Note that a text node can have child element nodes, for example:
626 @verbatim
627 <root>This is <b>bold</b></root>
628 @endverbatim
629
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700630 A text node can have 2 ways to output the next. "normal" output
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800631 and CDATA. It will default to the mode it was parsed from the XML file and
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700632 you generally want to leave it alone, but you can change the output mode with
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800633 SetCDATA() and query it with CDATA().
634*/
Lee Thomason5492a1c2012-01-23 15:32:10 -0800635class XMLText : public XMLNode
636{
Lee Thomason2c85a712012-01-31 08:24:24 -0800637 friend class XMLBase;
638 friend class XMLDocument;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800639public:
Lee Thomason56bdd022012-02-09 18:16:58 -0800640 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800641
Lee Thomason751da522012-02-10 08:50:51 -0800642 virtual XMLText* ToText() { return this; }
643 virtual const XMLText* ToText() const { return this; }
Lee Thomason5492a1c2012-01-23 15:32:10 -0800644
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800645 /// Declare whether this should be CDATA or standard text.
Lee Thomason5ce89412012-03-20 13:23:44 -0700646 void SetCData( bool _isCData ) { this->isCData = _isCData; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800647 /// Returns true if this is a CDATA text element.
Lee Thomason50f97b22012-02-11 16:33:40 -0800648 bool CData() const { return isCData; }
649
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800650 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800651 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
652 virtual bool ShallowEqual( const XMLNode* compare ) const;
653
Lee Thomason5492a1c2012-01-23 15:32:10 -0800654
655protected:
Lee Thomason50f97b22012-02-11 16:33:40 -0800656 XMLText( XMLDocument* doc ) : XMLNode( doc ), isCData( false ) {}
657 virtual ~XMLText() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800658 XMLText( const XMLText& ); // not supported
PKEuSc28ba3a2012-07-16 03:08:47 -0700659 XMLText& operator=( const XMLText& ); // not supported
Lee Thomason5492a1c2012-01-23 15:32:10 -0800660
661private:
Lee Thomason50f97b22012-02-11 16:33:40 -0800662 bool isCData;
Lee Thomason5492a1c2012-01-23 15:32:10 -0800663};
664
665
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800666/** An XML Comment. */
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800667class XMLComment : public XMLNode
668{
Lee Thomason2c85a712012-01-31 08:24:24 -0800669 friend class XMLDocument;
Lee Thomason3f57d272012-01-11 15:30:03 -0800670public:
Lee Thomason751da522012-02-10 08:50:51 -0800671 virtual XMLComment* ToComment() { return this; }
672 virtual const XMLComment* ToComment() const { return this; }
Lee Thomasonce0763e2012-01-11 15:43:54 -0800673
Lee Thomason56bdd022012-02-09 18:16:58 -0800674 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800675
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800676 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800677 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
678 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomasonce0763e2012-01-11 15:43:54 -0800679
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800680protected:
Lee Thomason2c85a712012-01-31 08:24:24 -0800681 XMLComment( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -0800682 virtual ~XMLComment();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800683 XMLComment( const XMLComment& ); // not supported
PKEuSc28ba3a2012-07-16 03:08:47 -0700684 XMLComment& operator=( const XMLComment& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800685
Lee Thomason3f57d272012-01-11 15:30:03 -0800686private:
U-Lama\Lee4cee6112011-12-31 14:58:18 -0800687};
U-Lama\Leee13c3e62011-12-28 14:36:55 -0800688
689
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800690/** In correct XML the declaration is the first entry in the file.
691 @verbatim
692 <?xml version="1.0" standalone="yes"?>
693 @endverbatim
694
695 TinyXML2 will happily read or write files without a declaration,
696 however.
697
698 The text of the declaration isn't interpreted. It is parsed
699 and written as a string.
700*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800701class XMLDeclaration : public XMLNode
702{
703 friend class XMLDocument;
704public:
705 virtual XMLDeclaration* ToDeclaration() { return this; }
706 virtual const XMLDeclaration* ToDeclaration() const { return this; }
707
708 virtual bool Accept( XMLVisitor* visitor ) const;
709
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800710 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800711 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
712 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800713
714protected:
715 XMLDeclaration( XMLDocument* doc );
716 virtual ~XMLDeclaration();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800717 XMLDeclaration( const XMLDeclaration& ); // not supported
PKEuSc28ba3a2012-07-16 03:08:47 -0700718 XMLDeclaration& operator=( const XMLDeclaration& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800719};
720
721
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800722/** Any tag that tinyXml doesn't recognize is saved as an
723 unknown. It is a tag of text, but should not be modified.
724 It will be written back to the XML, unchanged, when the file
725 is saved.
726
727 DTD tags get thrown into TiXmlUnknowns.
728*/
Lee Thomason50f97b22012-02-11 16:33:40 -0800729class XMLUnknown : public XMLNode
730{
731 friend class XMLDocument;
732public:
733 virtual XMLUnknown* ToUnknown() { return this; }
734 virtual const XMLUnknown* ToUnknown() const { return this; }
735
736 virtual bool Accept( XMLVisitor* visitor ) const;
737
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -0800738 char* ParseDeep( char*, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800739 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
740 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason50f97b22012-02-11 16:33:40 -0800741
742protected:
743 XMLUnknown( XMLDocument* doc );
744 virtual ~XMLUnknown();
Lee Thomason50adb4c2012-02-13 15:07:09 -0800745 XMLUnknown( const XMLUnknown& ); // not supported
PKEuSc28ba3a2012-07-16 03:08:47 -0700746 XMLUnknown& operator=( const XMLUnknown& ); // not supported
Lee Thomason50f97b22012-02-11 16:33:40 -0800747};
748
749
Lee Thomason1ff38e02012-02-14 18:18:16 -0800750enum {
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800751 XML_NO_ERROR = 0,
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800752 XML_SUCCESS = 0,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800753
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700754 XML_NO_ATTRIBUTE,
755 XML_WRONG_ATTRIBUTE_TYPE,
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -0800756
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700757 XML_ERROR_FILE_NOT_FOUND,
Lee Thomason7f7b1622012-03-24 12:49:03 -0700758 XML_ERROR_FILE_COULD_NOT_BE_OPENED,
Lee Thomasona3efec02012-06-15 14:30:44 -0700759 XML_ERROR_FILE_READ_ERROR,
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700760 XML_ERROR_ELEMENT_MISMATCH,
761 XML_ERROR_PARSING_ELEMENT,
762 XML_ERROR_PARSING_ATTRIBUTE,
763 XML_ERROR_IDENTIFYING_TAG,
764 XML_ERROR_PARSING_TEXT,
765 XML_ERROR_PARSING_CDATA,
766 XML_ERROR_PARSING_COMMENT,
767 XML_ERROR_PARSING_DECLARATION,
768 XML_ERROR_PARSING_UNKNOWN,
769 XML_ERROR_EMPTY_DOCUMENT,
770 XML_ERROR_MISMATCHED_ELEMENT,
Lee Thomason21be8822012-07-15 17:27:22 -0700771 XML_ERROR_PARSING,
772
773 XML_CAN_NOT_CONVERT_TEXT,
774 XML_NO_TEXT_NODE
Lee Thomason1ff38e02012-02-14 18:18:16 -0800775};
776
777
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800778/** An attribute is a name-value pair. Elements have an arbitrary
779 number of attributes, each with a unique name.
780
781 @note The attributes are not XMLNodes. You may only query the
782 Next() attribute in a list.
783*/
Lee Thomason56bdd022012-02-09 18:16:58 -0800784class XMLAttribute
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800785{
786 friend class XMLElement;
787public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800788 const char* Name() const { return name.GetStr(); } ///< The name of the attribute.
789 const char* Value() const { return value.GetStr(); } ///< The value of the attribute.
790 const XMLAttribute* Next() const { return next; } ///< The next attribute in the list.
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800791
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800792 /** IntAttribute interprets the attribute as an integer, and returns the value.
793 If the value isn't an integer, 0 will be returned. There is no error checking;
794 use QueryIntAttribute() if you need error checking.
795 */
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800796 int IntValue() const { int i=0; QueryIntValue( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800797 /// Query as an unsigned integer. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800798 unsigned UnsignedValue() const { unsigned i=0; QueryUnsignedValue( &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800799 /// Query as a boolean. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800800 bool BoolValue() const { bool b=false; QueryBoolValue( &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800801 /// Query as a double. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800802 double DoubleValue() const { double d=0; QueryDoubleValue( &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800803 /// Query as a float. See IntAttribute()
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800804 float FloatValue() const { float f=0; QueryFloatValue( &f ); return f; }
U-Stream\Leeae25a442012-02-17 17:48:16 -0800805
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800806 /** QueryIntAttribute interprets the attribute as an integer, and returns the value
807 in the provided paremeter. The function will return XML_NO_ERROR on success,
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700808 and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800809 */
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800810 int QueryIntValue( int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800811 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800812 int QueryUnsignedValue( unsigned int* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800813 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800814 int QueryBoolValue( bool* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800815 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800816 int QueryDoubleValue( double* value ) const;
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800817 /// See QueryIntAttribute
Lee Thomason7d00b9a2012-02-27 17:54:22 -0800818 int QueryFloatValue( float* value ) const;
Lee Thomason50adb4c2012-02-13 15:07:09 -0800819
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800820 /// Set the attribute to a string value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800821 void SetAttribute( const char* value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800822 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800823 void SetAttribute( int value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800824 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800825 void SetAttribute( unsigned value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800826 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800827 void SetAttribute( bool value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800828 /// Set the attribute to value.
Lee Thomason1ff38e02012-02-14 18:18:16 -0800829 void SetAttribute( double value );
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800830 /// Set the attribute to value.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800831 void SetAttribute( float value );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800832
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800833private:
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800834 enum { BUF_SIZE = 200 };
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800835
Lee Thomason (grinliz)9b093cc2012-02-25 21:30:18 -0800836 XMLAttribute() : next( 0 ) {}
Lee Thomasond1983222012-02-06 08:41:24 -0800837 virtual ~XMLAttribute() {}
Lee Thomason50adb4c2012-02-13 15:07:09 -0800838 XMLAttribute( const XMLAttribute& ); // not supported
839 void operator=( const XMLAttribute& ); // not supported
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800840 void SetName( const char* name );
Lee Thomason50adb4c2012-02-13 15:07:09 -0800841
Lee Thomason6f381b72012-03-02 12:59:39 -0800842 char* ParseDeep( char* p, bool processEntities );
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800843
Lee Thomason751da522012-02-10 08:50:51 -0800844 mutable StrPair name;
845 mutable StrPair value;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800846 XMLAttribute* next;
Lee Thomason43f59302012-02-06 18:18:11 -0800847 MemPool* memPool;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800848};
849
850
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800851/** The element is a container class. It has a value, the element name,
852 and can contain other elements, text, comments, and unknowns.
853 Elements also contain an arbitrary number of attributes.
854*/
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800855class XMLElement : public XMLNode
856{
Lee Thomason2c85a712012-01-31 08:24:24 -0800857 friend class XMLBase;
858 friend class XMLDocument;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800859public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800860 /// Get the name of an element (which is the Value() of the node.)
Lee Thomason2c85a712012-01-31 08:24:24 -0800861 const char* Name() const { return Value(); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800862 /// Set the name of the element.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800863 void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); }
Lee Thomason2c85a712012-01-31 08:24:24 -0800864
Lee Thomason751da522012-02-10 08:50:51 -0800865 virtual XMLElement* ToElement() { return this; }
866 virtual const XMLElement* ToElement() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -0800867 virtual bool Accept( XMLVisitor* visitor ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -0800868
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800869 /** Given an attribute name, Attribute() returns the value
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700870 for the attribute of that name, or null if none
Lee Thomason92258152012-03-24 13:05:39 -0700871 exists. For example:
872
873 @verbatim
874 const char* value = ele->Attribute( "foo" );
875 @endverbatim
876
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700877 The 'value' parameter is normally null. However, if specified,
878 the attribute will only be returned if the 'name' and 'value'
Lee Thomason92258152012-03-24 13:05:39 -0700879 match. This allow you to write code:
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700880
881 @verbatim
882 if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
883 @endverbatim
884
885 rather than:
886 @verbatim
887 if ( ele->Attribute( "foo" ) ) {
888 if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
889 }
890 @endverbatim
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800891 */
Lee Thomason8ba7f7d2012-03-24 13:04:04 -0700892 const char* Attribute( const char* name, const char* value=0 ) const;
Lee Thomason751da522012-02-10 08:50:51 -0800893
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800894 /** Given an attribute name, IntAttribute() returns the value
895 of the attribute interpreted as an integer. 0 will be
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700896 returned if there is an error. For a method with error
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800897 checking, see QueryIntAttribute()
898 */
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800899 int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800900 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800901 unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( name, &i ); return i; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800902 /// See IntAttribute()
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800903 bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( name, &b ); return b; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800904 /// See IntAttribute()
Thomas Roß08bdf502012-05-12 14:21:23 +0200905 double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( name, &d ); return d; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800906 /// See IntAttribute()
Thomas Roß08bdf502012-05-12 14:21:23 +0200907 float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( name, &f ); return f; }
U-Stream\Lee09a11c52012-02-17 08:31:16 -0800908
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700909 /** Given an attribute name, QueryIntAttribute() returns
Guillermo A. Amaral2eb70032012-03-20 11:26:57 -0700910 XML_NO_ERROR, XML_WRONG_ATTRIBUTE_TYPE if the conversion
911 can't be performed, or XML_NO_ATTRIBUTE if the attribute
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800912 doesn't exist. If successful, the result of the conversion
913 will be written to 'value'. If not successful, nothing will
914 be written to 'value'. This allows you to provide default
915 value:
916
917 @verbatim
918 int value = 10;
919 QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
920 @endverbatim
921 */
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700922 int QueryIntAttribute( const char* name, int* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryIntValue( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800923 /// See QueryIntAttribute()
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700924 int QueryUnsignedAttribute( const char* name, unsigned int* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryUnsignedValue( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800925 /// See QueryIntAttribute()
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700926 int QueryBoolAttribute( const char* name, bool* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryBoolValue( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800927 /// See QueryIntAttribute()
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700928 int QueryDoubleAttribute( const char* name, double* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryDoubleValue( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800929 /// See QueryIntAttribute()
Thomas Roß08bdf502012-05-12 14:21:23 +0200930 int QueryFloatAttribute( const char* name, float* _value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return XML_NO_ATTRIBUTE; return a->QueryFloatValue( _value ); }
Lee Thomason50f97b22012-02-11 16:33:40 -0800931
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800932 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700933 void SetAttribute( const char* name, const char* _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800934 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700935 void SetAttribute( const char* name, int _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800936 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700937 void SetAttribute( const char* name, unsigned _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800938 /// Sets the named attribute to value.
Guillermo A. Amaral9a6c6b82012-03-24 17:13:25 -0700939 void SetAttribute( const char* name, bool _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800940 /// Sets the named attribute to value.
Thomas Roß08bdf502012-05-12 14:21:23 +0200941 void SetAttribute( const char* name, double _value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( _value ); }
Lee Thomason50f97b22012-02-11 16:33:40 -0800942
U-Stream\Leeae25a442012-02-17 17:48:16 -0800943 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800944 Delete an attribute.
U-Stream\Leeae25a442012-02-17 17:48:16 -0800945 */
946 void DeleteAttribute( const char* name );
Lee Thomason751da522012-02-10 08:50:51 -0800947
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800948 /// Return the first attribute in the list.
Lee Thomason751da522012-02-10 08:50:51 -0800949 const XMLAttribute* FirstAttribute() const { return rootAttribute; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -0800950 /// Query a specific attribute in the list.
Lee Thomason1a1d4a72012-02-15 09:09:25 -0800951 const XMLAttribute* FindAttribute( const char* name ) const;
Lee Thomason751da522012-02-10 08:50:51 -0800952
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800953 /** Convenience function for easy access to the text inside an element. Although easy
954 and concise, GetText() is limited compared to getting the TiXmlText child
955 and accessing it directly.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700956
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800957 If the first child of 'this' is a TiXmlText, the GetText()
958 returns the character string of the Text node, else null is returned.
959
960 This is a convenient method for getting the text of simple contained text:
961 @verbatim
962 <foo>This is text</foo>
Lee Thomason21be8822012-07-15 17:27:22 -0700963 const char* str = fooElement->GetText();
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800964 @endverbatim
965
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700966 'str' will be a pointer to "This is text".
967
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800968 Note that this function can be misleading. If the element foo was created from
969 this XML:
970 @verbatim
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700971 <foo><b>This is text</b></foo>
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800972 @endverbatim
973
974 then the value of str would be null. The first child node isn't a text node, it is
975 another element. From this XML:
976 @verbatim
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700977 <foo>This is <b>text</b></foo>
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -0800978 @endverbatim
979 GetText() will return "This is ".
980 */
Lee Thomason50f97b22012-02-11 16:33:40 -0800981 const char* GetText() const;
Lee Thomason751da522012-02-10 08:50:51 -0800982
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -0700983 /**
Lee Thomason21be8822012-07-15 17:27:22 -0700984 Convenience method to query the value of a child text node. This is probably best
985 shown by example. Given you have a document is this form:
986 @verbatim
987 <point>
988 <x>1</x>
989 <y>1.4</y>
990 </point>
991 @endverbatim
992
993 The QueryIntText() and similar functions provide a safe and easier way to get to the
994 "value" of x and y.
995
996 @verbatim
997 int x = 0;
998 float y = 0; // types of x and y are contrived for example
999 const XMLElement* xElement = pointElement->FirstChildElement( "x" );
1000 const XMLElement* yElement = pointElement->FirstChildElement( "y" );
1001 xElement->QueryIntText( &x );
1002 yElement->QueryFloatText( &y );
1003 @endverbatim
1004
1005 @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted
1006 to the requested type, and XML_NO_TEXT_NODE if there is no child text to query.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001007
Lee Thomason21be8822012-07-15 17:27:22 -07001008 */
1009 int QueryIntText( int* _value ) const;
1010 /// See QueryIntText()
1011 int QueryUnsignedText( unsigned* _value ) const;
1012 /// See QueryIntText()
1013 int QueryBoolText( bool* _value ) const;
1014 /// See QueryIntText()
1015 int QueryDoubleText( double* _value ) const;
1016 /// See QueryIntText()
1017 int QueryFloatText( float* _value ) const;
1018
Lee Thomason2c85a712012-01-31 08:24:24 -08001019 // internal:
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001020 enum {
1021 OPEN, // <foo>
1022 CLOSED, // <foo/>
1023 CLOSING // </foo>
1024 };
1025 int ClosingType() const { return closingType; }
Lee Thomason (grinliz)7468f112012-02-24 08:56:50 -08001026 char* ParseDeep( char* p, StrPair* endTag );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001027 virtual XMLNode* ShallowClone( XMLDocument* document ) const;
1028 virtual bool ShallowEqual( const XMLNode* compare ) const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001029
Lee Thomason50adb4c2012-02-13 15:07:09 -08001030private:
Lee Thomason2c85a712012-01-31 08:24:24 -08001031 XMLElement( XMLDocument* doc );
Lee Thomasond1983222012-02-06 08:41:24 -08001032 virtual ~XMLElement();
Lee Thomason50adb4c2012-02-13 15:07:09 -08001033 XMLElement( const XMLElement& ); // not supported
1034 void operator=( const XMLElement& ); // not supported
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001035
Lee Thomason1a1d4a72012-02-15 09:09:25 -08001036 XMLAttribute* FindAttribute( const char* name );
1037 XMLAttribute* FindOrCreateAttribute( const char* name );
Lee Thomason5e3803c2012-04-16 08:57:05 -07001038 //void LinkAttribute( XMLAttribute* attrib );
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001039 char* ParseAttributes( char* p );
Lee Thomason67d61312012-01-24 16:01:51 -08001040
Lee Thomason (grinliz)46a14cf2012-02-23 22:27:28 -08001041 int closingType;
Lee Thomason5e3803c2012-04-16 08:57:05 -07001042 // The attribute list is ordered; there is no 'lastAttribute'
1043 // because the list needs to be scanned for dupes before adding
1044 // a new attribute.
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001045 XMLAttribute* rootAttribute;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001046};
1047
1048
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001049enum Whitespace {
1050 PRESERVE_WHITESPACE,
1051 COLLAPSE_WHITESPACE
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001052};
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001053
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001054
1055/** A Document binds together all the functionality.
Lee Thomason (grinliz)9c38d132012-02-24 21:50:50 -08001056 It can be saved, loaded, and printed to the screen.
1057 All Nodes are connected and allocated to a Document.
1058 If the Document is deleted, all its Nodes are also deleted.
1059*/
Lee Thomason67d61312012-01-24 16:01:51 -08001060class XMLDocument : public XMLNode
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001061{
Lee Thomasond1983222012-02-06 08:41:24 -08001062 friend class XMLElement;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001063public:
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001064 /// constructor
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001065 XMLDocument( bool processEntities = true, Whitespace = PRESERVE_WHITESPACE );
Lee Thomason3f57d272012-01-11 15:30:03 -08001066 ~XMLDocument();
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001067
Lee Thomason751da522012-02-10 08:50:51 -08001068 virtual XMLDocument* ToDocument() { return this; }
1069 virtual const XMLDocument* ToDocument() const { return this; }
Lee Thomason56bdd022012-02-09 18:16:58 -08001070
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001071 /**
1072 Parse an XML file from a character string.
1073 Returns XML_NO_ERROR (0) on success, or
1074 an errorID.
1075 */
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001076 int Parse( const char* xml );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001077
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001078 /**
1079 Load an XML file from disk.
1080 Returns XML_NO_ERROR (0) on success, or
1081 an errorID.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001082 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001083 int LoadFile( const char* filename );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001084
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001085 /**
1086 Load an XML file from disk. You are responsible
1087 for providing and closing the FILE*.
1088
1089 Returns XML_NO_ERROR (0) on success, or
1090 an errorID.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001091 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001092 int LoadFile( FILE* );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001093
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001094 /**
1095 Save the XML file to disk.
Ken Miller81da1fb2012-04-09 23:32:26 -05001096 Returns XML_NO_ERROR (0) on success, or
1097 an errorID.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001098 */
Robert Reif312a20f2012-09-08 19:33:57 -04001099 int SaveFile( const char* filename, bool compact = false );
Lee Thomasond11cd162012-04-12 08:35:36 -07001100
Ken Miller81da1fb2012-04-09 23:32:26 -05001101 /**
Thomas Roß08bdf502012-05-12 14:21:23 +02001102 Save the XML file to disk. You are responsible
Ken Miller81da1fb2012-04-09 23:32:26 -05001103 for providing and closing the FILE*.
1104
1105 Returns XML_NO_ERROR (0) on success, or
1106 an errorID.
1107 */
Robert Reif312a20f2012-09-08 19:33:57 -04001108 int SaveFile( FILE* fp, bool compact = false );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001109
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001110 bool ProcessEntities() const { return processEntities; }
1111 Whitespace WhitespaceMode() const { return whitespace; }
Lee Thomason6f381b72012-03-02 12:59:39 -08001112
1113 /**
1114 Returns true if this document has a leading Byte Order Mark of UTF8.
1115 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001116 bool HasBOM() const { return writeBOM; }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001117 /** Sets whether to write the BOM when writing the file.
1118 */
1119 void SetBOM( bool useBOM ) { writeBOM = useBOM; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001120
1121 /** Return the root element of DOM. Equivalent to FirstChildElement().
1122 To get the first node, use FirstChild().
1123 */
Lee Thomasond6277762012-02-22 16:00:12 -08001124 XMLElement* RootElement() { return FirstChildElement(); }
1125 const XMLElement* RootElement() const { return FirstChildElement(); }
Lee Thomason18d68bd2012-01-26 18:17:26 -08001126
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001127 /** Print the Document. If the Printer is not provided, it will
1128 print to stdout. If you provide Printer, this can print to a file:
1129 @verbatim
1130 XMLPrinter printer( fp );
1131 doc.Print( &printer );
1132 @endverbatim
1133
1134 Or you can use a printer to print to memory:
1135 @verbatim
1136 XMLPrinter printer;
1137 doc->Print( &printer );
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001138 // printer.CStr() has a const char* to the XML
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001139 @endverbatim
1140 */
1141 void Print( XMLPrinter* streamer=0 );
Lee Thomason56bdd022012-02-09 18:16:58 -08001142 virtual bool Accept( XMLVisitor* visitor ) const;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001143
Lee Thomason1ff38e02012-02-14 18:18:16 -08001144 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001145 Create a new Element associated with
1146 this Document. The memory for the Element
1147 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001148 */
Lee Thomason2c85a712012-01-31 08:24:24 -08001149 XMLElement* NewElement( const char* name );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001150 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001151 Create a new Comment associated with
1152 this Document. The memory for the Comment
1153 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001154 */
1155 XMLComment* NewComment( const char* comment );
1156 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001157 Create a new Text associated with
1158 this Document. The memory for the Text
1159 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001160 */
1161 XMLText* NewText( const char* text );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001162 /**
1163 Create a new Declaration associated with
1164 this Document. The memory for the object
1165 is managed by the Document.
Lee Thomasonf68c4382012-04-28 14:37:11 -07001166
1167 If the 'text' param is null, the standard
1168 declaration is used.:
1169 @verbatim
1170 <?xml version="1.0" encoding="UTF-8"?>
1171 @endverbatim
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001172 */
Lee Thomasonf68c4382012-04-28 14:37:11 -07001173 XMLDeclaration* NewDeclaration( const char* text=0 );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001174 /**
1175 Create a new Unknown associated with
1176 this Document. The memory for the object
1177 is managed by the Document.
1178 */
1179 XMLUnknown* NewUnknown( const char* text );
Lee Thomason2c85a712012-01-31 08:24:24 -08001180
U-Stream\Leeae25a442012-02-17 17:48:16 -08001181 /**
Thomas Roß08bdf502012-05-12 14:21:23 +02001182 Delete a node associated with this document.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001183 It will be unlinked from the DOM.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001184 */
1185 void DeleteNode( XMLNode* node ) { node->parent->DeleteChild( node ); }
1186
Lee Thomason67d61312012-01-24 16:01:51 -08001187 void SetError( int error, const char* str1, const char* str2 );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001188
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001189 /// Return true if there was an error parsing the document.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001190 bool Error() const { return errorID != XML_NO_ERROR; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001191 /// Return the errorID.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001192 int ErrorID() const { return errorID; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001193 /// Return a possibly helpful diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001194 const char* GetErrorStr1() const { return errorStr1; }
Thomas Roß08bdf502012-05-12 14:21:23 +02001195 /// Return a possibly helpful secondary diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001196 const char* GetErrorStr2() const { return errorStr2; }
Thomas Roß08bdf502012-05-12 14:21:23 +02001197 /// If there is an error, print it to stdout.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001198 void PrintError() const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001199
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001200 // internal
Lee Thomasond1983222012-02-06 08:41:24 -08001201 char* Identify( char* p, XMLNode** node );
Lee Thomason2c85a712012-01-31 08:24:24 -08001202
Lee Thomason6f381b72012-03-02 12:59:39 -08001203 virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { return 0; }
1204 virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { return false; }
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001205
Lee Thomason3f57d272012-01-11 15:30:03 -08001206private:
Lee Thomason50adb4c2012-02-13 15:07:09 -08001207 XMLDocument( const XMLDocument& ); // not supported
1208 void operator=( const XMLDocument& ); // not supported
Lee Thomason18d68bd2012-01-26 18:17:26 -08001209 void InitDocument();
1210
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001211 bool writeBOM;
Lee Thomason6f381b72012-03-02 12:59:39 -08001212 bool processEntities;
Lee Thomason7c913cd2012-01-26 18:32:34 -08001213 int errorID;
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001214 Whitespace whitespace;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001215 const char* errorStr1;
1216 const char* errorStr2;
1217 char* charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001218
1219 MemPoolT< sizeof(XMLElement) > elementPool;
1220 MemPoolT< sizeof(XMLAttribute) > attributePool;
1221 MemPoolT< sizeof(XMLText) > textPool;
1222 MemPoolT< sizeof(XMLComment) > commentPool;
Lee Thomason5cae8972012-01-24 18:03:07 -08001223};
1224
Lee Thomason7c913cd2012-01-26 18:32:34 -08001225
Lee Thomason3ffdd392012-03-28 17:27:55 -07001226/**
1227 A XMLHandle is a class that wraps a node pointer with null checks; this is
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001228 an incredibly useful thing. Note that XMLHandle is not part of the TinyXML
Lee Thomason3ffdd392012-03-28 17:27:55 -07001229 DOM structure. It is a separate utility class.
1230
1231 Take an example:
1232 @verbatim
1233 <Document>
1234 <Element attributeA = "valueA">
1235 <Child attributeB = "value1" />
1236 <Child attributeB = "value2" />
1237 </Element>
Thomas Roß08bdf502012-05-12 14:21:23 +02001238 </Document>
Lee Thomason3ffdd392012-03-28 17:27:55 -07001239 @endverbatim
1240
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001241 Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
Lee Thomason3ffdd392012-03-28 17:27:55 -07001242 easy to write a *lot* of code that looks like:
1243
1244 @verbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001245 XMLElement* root = document.FirstChildElement( "Document" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001246 if ( root )
1247 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001248 XMLElement* element = root->FirstChildElement( "Element" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001249 if ( element )
1250 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001251 XMLElement* child = element->FirstChildElement( "Child" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001252 if ( child )
1253 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001254 XMLElement* child2 = child->NextSiblingElement( "Child" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001255 if ( child2 )
1256 {
1257 // Finally do something useful.
1258 @endverbatim
1259
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001260 And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001261 of such code. A XMLHandle checks for null pointers so it is perfectly safe
Lee Thomason3ffdd392012-03-28 17:27:55 -07001262 and correct to use:
1263
1264 @verbatim
Lee Thomasondb0bbb62012-04-04 15:47:04 -07001265 XMLHandle docHandle( &document );
1266 XMLElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild().NextSibling().ToElement();
Lee Thomason3ffdd392012-03-28 17:27:55 -07001267 if ( child2 )
1268 {
1269 // do something useful
1270 @endverbatim
1271
1272 Which is MUCH more concise and useful.
1273
1274 It is also safe to copy handles - internally they are nothing more than node pointers.
1275 @verbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001276 XMLHandle handleCopy = handle;
Lee Thomason3ffdd392012-03-28 17:27:55 -07001277 @endverbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001278
1279 See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001280*/
1281class XMLHandle
1282{
1283public:
1284 /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
Lee Thomason8b899812012-04-04 15:58:16 -07001285 XMLHandle( XMLNode* _node ) { node = _node; }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001286 /// Create a handle from a node.
Lee Thomason8b899812012-04-04 15:58:16 -07001287 XMLHandle( XMLNode& _node ) { node = &_node; }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001288 /// Copy constructor
Lee Thomason8b899812012-04-04 15:58:16 -07001289 XMLHandle( const XMLHandle& ref ) { node = ref.node; }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001290 /// Assignment
PKEuSc28ba3a2012-07-16 03:08:47 -07001291 XMLHandle& operator=( const XMLHandle& ref ) { node = ref.node; return *this; }
Lee Thomason3ffdd392012-03-28 17:27:55 -07001292
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001293 /// Get the first child of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001294 XMLHandle FirstChild() { return XMLHandle( node ? node->FirstChild() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001295 /// Get the first child element of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001296 XMLHandle FirstChildElement( const char* value=0 ) { return XMLHandle( node ? node->FirstChildElement( value ) : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001297 /// Get the last child of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001298 XMLHandle LastChild() { return XMLHandle( node ? node->LastChild() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001299 /// Get the last child element of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001300 XMLHandle LastChildElement( const char* _value=0 ) { return XMLHandle( node ? node->LastChildElement( _value ) : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001301 /// Get the previous sibling of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001302 XMLHandle PreviousSibling() { return XMLHandle( node ? node->PreviousSibling() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001303 /// Get the previous sibling element of this handle.
Lee Thomason5708f812012-03-28 17:46:41 -07001304 XMLHandle PreviousSiblingElement( const char* _value=0 ) { return XMLHandle( node ? node->PreviousSiblingElement( _value ) : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001305 /// Get the next sibling of this handle.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001306 XMLHandle NextSibling() { return XMLHandle( node ? node->NextSibling() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001307 /// Get the next sibling element of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001308 XMLHandle NextSiblingElement( const char* _value=0 ) { return XMLHandle( node ? node->NextSiblingElement( _value ) : 0 ); }
Lee Thomason3ffdd392012-03-28 17:27:55 -07001309
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001310 /// Safe cast to XMLNode. This can return null.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001311 XMLNode* ToNode() { return node; }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001312 /// Safe cast to XMLElement. This can return null.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001313 XMLElement* ToElement() { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001314 /// Safe cast to XMLText. This can return null.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001315 XMLText* ToText() { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001316 /// Safe cast to XMLUnknown. This can return null.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001317 XMLUnknown* ToUnknown() { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001318 /// Safe cast to XMLDeclaration. This can return null.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001319 XMLDeclaration* ToDeclaration() { return ( ( node && node->ToDeclaration() ) ? node->ToDeclaration() : 0 ); }
Lee Thomason3ffdd392012-03-28 17:27:55 -07001320
1321private:
1322 XMLNode* node;
1323};
1324
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001325
1326/**
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001327 A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the
1328 same in all regards, except for the 'const' qualifiers. See XMLHandle for API.
Lee Thomason8b899812012-04-04 15:58:16 -07001329*/
1330class XMLConstHandle
1331{
1332public:
1333 XMLConstHandle( const XMLNode* _node ) { node = _node; }
1334 XMLConstHandle( const XMLNode& _node ) { node = &_node; }
1335 XMLConstHandle( const XMLConstHandle& ref ) { node = ref.node; }
1336
PKEuSc28ba3a2012-07-16 03:08:47 -07001337 XMLConstHandle& operator=( const XMLConstHandle& ref ) { node = ref.node; return *this; }
Lee Thomason8b899812012-04-04 15:58:16 -07001338
1339 const XMLConstHandle FirstChild() const { return XMLConstHandle( node ? node->FirstChild() : 0 ); }
1340 const XMLConstHandle FirstChildElement( const char* value=0 ) const { return XMLConstHandle( node ? node->FirstChildElement( value ) : 0 ); }
1341 const XMLConstHandle LastChild() const { return XMLConstHandle( node ? node->LastChild() : 0 ); }
1342 const XMLConstHandle LastChildElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->LastChildElement( _value ) : 0 ); }
1343 const XMLConstHandle PreviousSibling() const { return XMLConstHandle( node ? node->PreviousSibling() : 0 ); }
1344 const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->PreviousSiblingElement( _value ) : 0 ); }
1345 const XMLConstHandle NextSibling() const { return XMLConstHandle( node ? node->NextSibling() : 0 ); }
1346 const XMLConstHandle NextSiblingElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->NextSiblingElement( _value ) : 0 ); }
1347
1348
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001349 const XMLNode* ToNode() const { return node; }
Lee Thomason8b899812012-04-04 15:58:16 -07001350 const XMLElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
1351 const XMLText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
1352 const XMLUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001353 const XMLDeclaration* ToDeclaration() const { return ( ( node && node->ToDeclaration() ) ? node->ToDeclaration() : 0 ); }
1354
Lee Thomason5cae8972012-01-24 18:03:07 -08001355private:
Lee Thomason8b899812012-04-04 15:58:16 -07001356 const XMLNode* node;
Lee Thomason56bdd022012-02-09 18:16:58 -08001357};
Lee Thomason6f381b72012-03-02 12:59:39 -08001358
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001359
1360/**
1361 Printing functionality. The XMLPrinter gives you more
1362 options than the XMLDocument::Print() method.
1363
1364 It can:
1365 -# Print to memory.
Thomas Roß08bdf502012-05-12 14:21:23 +02001366 -# Print to a file you provide.
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001367 -# Print XML without a XMLDocument.
1368
1369 Print to Memory
1370
1371 @verbatim
1372 XMLPrinter printer;
1373 doc->Print( &printer );
Thomas Roß08bdf502012-05-12 14:21:23 +02001374 SomeFunction( printer.CStr() );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001375 @endverbatim
1376
1377 Print to a File
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001378
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001379 You provide the file pointer.
1380 @verbatim
1381 XMLPrinter printer( fp );
1382 doc.Print( &printer );
1383 @endverbatim
1384
1385 Print without a XMLDocument
1386
1387 When loading, an XML parser is very useful. However, sometimes
1388 when saving, it just gets in the way. The code is often set up
1389 for streaming, and constructing the DOM is just overhead.
1390
1391 The Printer supports the streaming case. The following code
1392 prints out a trivially simple XML file without ever creating
1393 an XML document.
1394
1395 @verbatim
1396 XMLPrinter printer( fp );
1397 printer.OpenElement( "foo" );
1398 printer.PushAttribute( "foo", "bar" );
1399 printer.CloseElement();
1400 @endverbatim
1401*/
1402class XMLPrinter : public XMLVisitor
1403{
1404public:
1405 /** Construct the printer. If the FILE* is specified,
1406 this will print to the FILE. Else it will print
Lee Thomason4cd85342012-06-04 17:02:37 -07001407 to memory, and the result is available in CStr().
1408 If 'compact' is set to true, then output is created
1409 with only required whitespace and newlines.
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001410 */
sniperbat25900882012-05-28 17:22:07 +08001411 XMLPrinter( FILE* file=0, bool compact = false );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001412 ~XMLPrinter() {}
1413
1414 /** If streaming, write the BOM and declaration. */
1415 void PushHeader( bool writeBOM, bool writeDeclaration );
1416 /** If streaming, start writing an element.
1417 The element must be closed with CloseElement()
1418 */
1419 void OpenElement( const char* name );
1420 /// If streaming, add an attribute to an open element.
1421 void PushAttribute( const char* name, const char* value );
1422 void PushAttribute( const char* name, int value );
1423 void PushAttribute( const char* name, unsigned value );
1424 void PushAttribute( const char* name, bool value );
1425 void PushAttribute( const char* name, double value );
1426 /// If streaming, close the Element.
1427 void CloseElement();
1428
1429 /// Add a text node.
1430 void PushText( const char* text, bool cdata=false );
Lee Thomason21be8822012-07-15 17:27:22 -07001431 /// Add a text node from an integer.
1432 void PushText( int value );
1433 /// Add a text node from an unsigned.
1434 void PushText( unsigned value );
1435 /// Add a text node from a bool.
1436 void PushText( bool value );
1437 /// Add a text node from a float.
1438 void PushText( float value );
1439 /// Add a text node from a double.
1440 void PushText( double value );
1441
1442 /// Add a comment
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001443 void PushComment( const char* comment );
1444
1445 void PushDeclaration( const char* value );
1446 void PushUnknown( const char* value );
1447
1448 virtual bool VisitEnter( const XMLDocument& /*doc*/ );
1449 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
1450
1451 virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
1452 virtual bool VisitExit( const XMLElement& element );
1453
1454 virtual bool Visit( const XMLText& text );
1455 virtual bool Visit( const XMLComment& comment );
1456 virtual bool Visit( const XMLDeclaration& declaration );
1457 virtual bool Visit( const XMLUnknown& unknown );
1458
1459 /**
1460 If in print to memory mode, return a pointer to
1461 the XML file in memory.
1462 */
1463 const char* CStr() const { return buffer.Mem(); }
sniperbate01e7862012-05-21 12:45:36 +08001464 /**
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001465 If in print to memory mode, return the size
Lee Thomason (grinliz)48ea0bc2012-05-26 14:41:14 -07001466 of the XML file in memory. (Note the size returned
1467 includes the terminating null.)
sniperbate01e7862012-05-21 12:45:36 +08001468 */
Lee Thomasonc78dc012012-06-12 13:12:15 -07001469 int CStrSize() const { return buffer.Size(); }
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001470
1471private:
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001472 void SealElement();
1473 void PrintSpace( int depth );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001474 void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
1475 void Print( const char* format, ... );
1476
1477 bool elementJustOpened;
1478 bool firstElement;
1479 FILE* fp;
1480 int depth;
1481 int textDepth;
1482 bool processEntities;
sniperbat25900882012-05-28 17:22:07 +08001483 bool compactMode;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001484
1485 enum {
1486 ENTITY_RANGE = 64,
1487 BUF_SIZE = 200
1488 };
1489 bool entityFlag[ENTITY_RANGE];
1490 bool restrictedEntityFlag[ENTITY_RANGE];
1491
1492 DynArray< const char*, 10 > stack;
PKEuSe736f292012-07-16 03:27:55 -07001493 DynArray< char, 20 > buffer;
1494#ifdef _MSC_VER
1495 DynArray< char, 20 > accumulator;
1496#endif
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001497};
1498
1499
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -07001500} // tinyxml2
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001501
1502
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001503#endif // TINYXML2_INCLUDED