blob: 27304abdff2e88962de65c1b585d3dc0f8ff41c5 [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)fc6320e2012-09-23 20:25:50 -070098static const int TIXML2_PATCH_VERSION = 8;
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.
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001075
1076 You may optionally pass in the 'nBytes', which is
1077 the number of bytes which will be parsed. If not
1078 specified, TinyXML will assume 'xml' points to a
1079 null terminated string.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001080 */
Lee Thomason (grinliz)e2bcb322012-09-17 17:58:25 -07001081 int Parse( const char* xml, size_t nBytes=(size_t)(-1) );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001082
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001083 /**
1084 Load an XML file from disk.
1085 Returns XML_NO_ERROR (0) on success, or
1086 an errorID.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001087 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001088 int LoadFile( const char* filename );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001089
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001090 /**
1091 Load an XML file from disk. You are responsible
1092 for providing and closing the FILE*.
1093
1094 Returns XML_NO_ERROR (0) on success, or
1095 an errorID.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001096 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001097 int LoadFile( FILE* );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001098
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001099 /**
1100 Save the XML file to disk.
Ken Miller81da1fb2012-04-09 23:32:26 -05001101 Returns XML_NO_ERROR (0) on success, or
1102 an errorID.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001103 */
Robert Reif312a20f2012-09-08 19:33:57 -04001104 int SaveFile( const char* filename, bool compact = false );
Lee Thomasond11cd162012-04-12 08:35:36 -07001105
Ken Miller81da1fb2012-04-09 23:32:26 -05001106 /**
Thomas Roß08bdf502012-05-12 14:21:23 +02001107 Save the XML file to disk. You are responsible
Ken Miller81da1fb2012-04-09 23:32:26 -05001108 for providing and closing the FILE*.
1109
1110 Returns XML_NO_ERROR (0) on success, or
1111 an errorID.
1112 */
Robert Reif312a20f2012-09-08 19:33:57 -04001113 int SaveFile( FILE* fp, bool compact = false );
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001114
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001115 bool ProcessEntities() const { return processEntities; }
1116 Whitespace WhitespaceMode() const { return whitespace; }
Lee Thomason6f381b72012-03-02 12:59:39 -08001117
1118 /**
1119 Returns true if this document has a leading Byte Order Mark of UTF8.
1120 */
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001121 bool HasBOM() const { return writeBOM; }
Lee Thomasonf68c4382012-04-28 14:37:11 -07001122 /** Sets whether to write the BOM when writing the file.
1123 */
1124 void SetBOM( bool useBOM ) { writeBOM = useBOM; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001125
1126 /** Return the root element of DOM. Equivalent to FirstChildElement().
1127 To get the first node, use FirstChild().
1128 */
Lee Thomasond6277762012-02-22 16:00:12 -08001129 XMLElement* RootElement() { return FirstChildElement(); }
1130 const XMLElement* RootElement() const { return FirstChildElement(); }
Lee Thomason18d68bd2012-01-26 18:17:26 -08001131
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001132 /** Print the Document. If the Printer is not provided, it will
1133 print to stdout. If you provide Printer, this can print to a file:
1134 @verbatim
1135 XMLPrinter printer( fp );
1136 doc.Print( &printer );
1137 @endverbatim
1138
1139 Or you can use a printer to print to memory:
1140 @verbatim
1141 XMLPrinter printer;
1142 doc->Print( &printer );
Lee Thomason (grinliz)28129862012-02-25 21:11:20 -08001143 // printer.CStr() has a const char* to the XML
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001144 @endverbatim
1145 */
1146 void Print( XMLPrinter* streamer=0 );
Lee Thomason56bdd022012-02-09 18:16:58 -08001147 virtual bool Accept( XMLVisitor* visitor ) const;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001148
Lee Thomason1ff38e02012-02-14 18:18:16 -08001149 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001150 Create a new Element associated with
1151 this Document. The memory for the Element
1152 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001153 */
Lee Thomason2c85a712012-01-31 08:24:24 -08001154 XMLElement* NewElement( const char* name );
Lee Thomason1ff38e02012-02-14 18:18:16 -08001155 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001156 Create a new Comment associated with
1157 this Document. The memory for the Comment
1158 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001159 */
1160 XMLComment* NewComment( const char* comment );
1161 /**
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001162 Create a new Text associated with
1163 this Document. The memory for the Text
1164 is managed by the Document.
Lee Thomason1ff38e02012-02-14 18:18:16 -08001165 */
1166 XMLText* NewText( const char* text );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001167 /**
1168 Create a new Declaration associated with
1169 this Document. The memory for the object
1170 is managed by the Document.
Lee Thomasonf68c4382012-04-28 14:37:11 -07001171
1172 If the 'text' param is null, the standard
1173 declaration is used.:
1174 @verbatim
1175 <?xml version="1.0" encoding="UTF-8"?>
1176 @endverbatim
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001177 */
Lee Thomasonf68c4382012-04-28 14:37:11 -07001178 XMLDeclaration* NewDeclaration( const char* text=0 );
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001179 /**
1180 Create a new Unknown associated with
1181 this Document. The memory for the object
1182 is managed by the Document.
1183 */
1184 XMLUnknown* NewUnknown( const char* text );
Lee Thomason2c85a712012-01-31 08:24:24 -08001185
U-Stream\Leeae25a442012-02-17 17:48:16 -08001186 /**
Thomas Roß08bdf502012-05-12 14:21:23 +02001187 Delete a node associated with this document.
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001188 It will be unlinked from the DOM.
U-Stream\Leeae25a442012-02-17 17:48:16 -08001189 */
1190 void DeleteNode( XMLNode* node ) { node->parent->DeleteChild( node ); }
1191
Lee Thomason67d61312012-01-24 16:01:51 -08001192 void SetError( int error, const char* str1, const char* str2 );
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001193
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001194 /// Return true if there was an error parsing the document.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001195 bool Error() const { return errorID != XML_NO_ERROR; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001196 /// Return the errorID.
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001197 int ErrorID() const { return errorID; }
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001198 /// Return a possibly helpful diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001199 const char* GetErrorStr1() const { return errorStr1; }
Thomas Roß08bdf502012-05-12 14:21:23 +02001200 /// Return a possibly helpful secondary diagnostic location or string.
Lee Thomason18d68bd2012-01-26 18:17:26 -08001201 const char* GetErrorStr2() const { return errorStr2; }
Thomas Roß08bdf502012-05-12 14:21:23 +02001202 /// If there is an error, print it to stdout.
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001203 void PrintError() const;
Lee Thomason8a5dfee2012-01-18 17:43:40 -08001204
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001205 // internal
Lee Thomasond1983222012-02-06 08:41:24 -08001206 char* Identify( char* p, XMLNode** node );
Lee Thomason2c85a712012-01-31 08:24:24 -08001207
Lee Thomason6f381b72012-03-02 12:59:39 -08001208 virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { return 0; }
1209 virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const { return false; }
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001210
Lee Thomason3f57d272012-01-11 15:30:03 -08001211private:
Lee Thomason50adb4c2012-02-13 15:07:09 -08001212 XMLDocument( const XMLDocument& ); // not supported
1213 void operator=( const XMLDocument& ); // not supported
Lee Thomason18d68bd2012-01-26 18:17:26 -08001214 void InitDocument();
1215
Lee Thomason (grinliz)68db57e2012-02-21 09:08:12 -08001216 bool writeBOM;
Lee Thomason6f381b72012-03-02 12:59:39 -08001217 bool processEntities;
Lee Thomason7c913cd2012-01-26 18:32:34 -08001218 int errorID;
Lee Thomason (grinliz)bc1bfb72012-08-20 22:00:38 -07001219 Whitespace whitespace;
Lee Thomason18d68bd2012-01-26 18:17:26 -08001220 const char* errorStr1;
1221 const char* errorStr2;
1222 char* charBuffer;
Lee Thomasond1983222012-02-06 08:41:24 -08001223
1224 MemPoolT< sizeof(XMLElement) > elementPool;
1225 MemPoolT< sizeof(XMLAttribute) > attributePool;
1226 MemPoolT< sizeof(XMLText) > textPool;
1227 MemPoolT< sizeof(XMLComment) > commentPool;
Lee Thomason5cae8972012-01-24 18:03:07 -08001228};
1229
Lee Thomason7c913cd2012-01-26 18:32:34 -08001230
Lee Thomason3ffdd392012-03-28 17:27:55 -07001231/**
1232 A XMLHandle is a class that wraps a node pointer with null checks; this is
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001233 an incredibly useful thing. Note that XMLHandle is not part of the TinyXML
Lee Thomason3ffdd392012-03-28 17:27:55 -07001234 DOM structure. It is a separate utility class.
1235
1236 Take an example:
1237 @verbatim
1238 <Document>
1239 <Element attributeA = "valueA">
1240 <Child attributeB = "value1" />
1241 <Child attributeB = "value2" />
1242 </Element>
Thomas Roß08bdf502012-05-12 14:21:23 +02001243 </Document>
Lee Thomason3ffdd392012-03-28 17:27:55 -07001244 @endverbatim
1245
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001246 Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
Lee Thomason3ffdd392012-03-28 17:27:55 -07001247 easy to write a *lot* of code that looks like:
1248
1249 @verbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001250 XMLElement* root = document.FirstChildElement( "Document" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001251 if ( root )
1252 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001253 XMLElement* element = root->FirstChildElement( "Element" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001254 if ( element )
1255 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001256 XMLElement* child = element->FirstChildElement( "Child" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001257 if ( child )
1258 {
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001259 XMLElement* child2 = child->NextSiblingElement( "Child" );
Lee Thomason3ffdd392012-03-28 17:27:55 -07001260 if ( child2 )
1261 {
1262 // Finally do something useful.
1263 @endverbatim
1264
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001265 And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001266 of such code. A XMLHandle checks for null pointers so it is perfectly safe
Lee Thomason3ffdd392012-03-28 17:27:55 -07001267 and correct to use:
1268
1269 @verbatim
Lee Thomasondb0bbb62012-04-04 15:47:04 -07001270 XMLHandle docHandle( &document );
1271 XMLElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild().NextSibling().ToElement();
Lee Thomason3ffdd392012-03-28 17:27:55 -07001272 if ( child2 )
1273 {
1274 // do something useful
1275 @endverbatim
1276
1277 Which is MUCH more concise and useful.
1278
1279 It is also safe to copy handles - internally they are nothing more than node pointers.
1280 @verbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001281 XMLHandle handleCopy = handle;
Lee Thomason3ffdd392012-03-28 17:27:55 -07001282 @endverbatim
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001283
1284 See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001285*/
1286class XMLHandle
1287{
1288public:
1289 /// 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 -07001290 XMLHandle( XMLNode* _node ) { node = _node; }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001291 /// Create a handle from a node.
Lee Thomason8b899812012-04-04 15:58:16 -07001292 XMLHandle( XMLNode& _node ) { node = &_node; }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001293 /// Copy constructor
Lee Thomason8b899812012-04-04 15:58:16 -07001294 XMLHandle( const XMLHandle& ref ) { node = ref.node; }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001295 /// Assignment
PKEuSc28ba3a2012-07-16 03:08:47 -07001296 XMLHandle& operator=( const XMLHandle& ref ) { node = ref.node; return *this; }
Lee Thomason3ffdd392012-03-28 17:27:55 -07001297
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001298 /// Get the first child of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001299 XMLHandle FirstChild() { return XMLHandle( node ? node->FirstChild() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001300 /// Get the first child element of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001301 XMLHandle FirstChildElement( const char* value=0 ) { return XMLHandle( node ? node->FirstChildElement( value ) : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001302 /// Get the last child of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001303 XMLHandle LastChild() { return XMLHandle( node ? node->LastChild() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001304 /// Get the last child element of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001305 XMLHandle LastChildElement( const char* _value=0 ) { return XMLHandle( node ? node->LastChildElement( _value ) : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001306 /// Get the previous sibling of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001307 XMLHandle PreviousSibling() { return XMLHandle( node ? node->PreviousSibling() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001308 /// Get the previous sibling element of this handle.
Lee Thomason5708f812012-03-28 17:46:41 -07001309 XMLHandle PreviousSiblingElement( const char* _value=0 ) { return XMLHandle( node ? node->PreviousSiblingElement( _value ) : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001310 /// Get the next sibling of this handle.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001311 XMLHandle NextSibling() { return XMLHandle( node ? node->NextSibling() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001312 /// Get the next sibling element of this handle.
Lee Thomason8b899812012-04-04 15:58:16 -07001313 XMLHandle NextSiblingElement( const char* _value=0 ) { return XMLHandle( node ? node->NextSiblingElement( _value ) : 0 ); }
Lee Thomason3ffdd392012-03-28 17:27:55 -07001314
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001315 /// Safe cast to XMLNode. This can return null.
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001316 XMLNode* ToNode() { return node; }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001317 /// Safe cast to XMLElement. This can return null.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001318 XMLElement* ToElement() { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001319 /// Safe cast to XMLText. This can return null.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001320 XMLText* ToText() { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001321 /// Safe cast to XMLUnknown. This can return null.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001322 XMLUnknown* ToUnknown() { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001323 /// Safe cast to XMLDeclaration. This can return null.
Lee Thomason3ffdd392012-03-28 17:27:55 -07001324 XMLDeclaration* ToDeclaration() { return ( ( node && node->ToDeclaration() ) ? node->ToDeclaration() : 0 ); }
Lee Thomason3ffdd392012-03-28 17:27:55 -07001325
1326private:
1327 XMLNode* node;
1328};
1329
Lee Thomason (grinliz)2a1cd272012-02-24 17:37:53 -08001330
1331/**
Lee Thomason (grinliz)ae209f62012-04-04 22:00:07 -07001332 A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the
1333 same in all regards, except for the 'const' qualifiers. See XMLHandle for API.
Lee Thomason8b899812012-04-04 15:58:16 -07001334*/
1335class XMLConstHandle
1336{
1337public:
1338 XMLConstHandle( const XMLNode* _node ) { node = _node; }
1339 XMLConstHandle( const XMLNode& _node ) { node = &_node; }
1340 XMLConstHandle( const XMLConstHandle& ref ) { node = ref.node; }
1341
PKEuSc28ba3a2012-07-16 03:08:47 -07001342 XMLConstHandle& operator=( const XMLConstHandle& ref ) { node = ref.node; return *this; }
Lee Thomason8b899812012-04-04 15:58:16 -07001343
1344 const XMLConstHandle FirstChild() const { return XMLConstHandle( node ? node->FirstChild() : 0 ); }
1345 const XMLConstHandle FirstChildElement( const char* value=0 ) const { return XMLConstHandle( node ? node->FirstChildElement( value ) : 0 ); }
1346 const XMLConstHandle LastChild() const { return XMLConstHandle( node ? node->LastChild() : 0 ); }
1347 const XMLConstHandle LastChildElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->LastChildElement( _value ) : 0 ); }
1348 const XMLConstHandle PreviousSibling() const { return XMLConstHandle( node ? node->PreviousSibling() : 0 ); }
1349 const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->PreviousSiblingElement( _value ) : 0 ); }
1350 const XMLConstHandle NextSibling() const { return XMLConstHandle( node ? node->NextSibling() : 0 ); }
1351 const XMLConstHandle NextSiblingElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->NextSiblingElement( _value ) : 0 ); }
1352
1353
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001354 const XMLNode* ToNode() const { return node; }
Lee Thomason8b899812012-04-04 15:58:16 -07001355 const XMLElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
1356 const XMLText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
1357 const XMLUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
Lee Thomason (grinliz)bd0a8ac2012-02-20 20:14:33 -08001358 const XMLDeclaration* ToDeclaration() const { return ( ( node && node->ToDeclaration() ) ? node->ToDeclaration() : 0 ); }
1359
Lee Thomason5cae8972012-01-24 18:03:07 -08001360private:
Lee Thomason8b899812012-04-04 15:58:16 -07001361 const XMLNode* node;
Lee Thomason56bdd022012-02-09 18:16:58 -08001362};
Lee Thomason6f381b72012-03-02 12:59:39 -08001363
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001364
1365/**
1366 Printing functionality. The XMLPrinter gives you more
1367 options than the XMLDocument::Print() method.
1368
1369 It can:
1370 -# Print to memory.
Thomas Roß08bdf502012-05-12 14:21:23 +02001371 -# Print to a file you provide.
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001372 -# Print XML without a XMLDocument.
1373
1374 Print to Memory
1375
1376 @verbatim
1377 XMLPrinter printer;
1378 doc->Print( &printer );
Thomas Roß08bdf502012-05-12 14:21:23 +02001379 SomeFunction( printer.CStr() );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001380 @endverbatim
1381
1382 Print to a File
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001383
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001384 You provide the file pointer.
1385 @verbatim
1386 XMLPrinter printer( fp );
1387 doc.Print( &printer );
1388 @endverbatim
1389
1390 Print without a XMLDocument
1391
1392 When loading, an XML parser is very useful. However, sometimes
1393 when saving, it just gets in the way. The code is often set up
1394 for streaming, and constructing the DOM is just overhead.
1395
1396 The Printer supports the streaming case. The following code
1397 prints out a trivially simple XML file without ever creating
1398 an XML document.
1399
1400 @verbatim
1401 XMLPrinter printer( fp );
1402 printer.OpenElement( "foo" );
1403 printer.PushAttribute( "foo", "bar" );
1404 printer.CloseElement();
1405 @endverbatim
1406*/
1407class XMLPrinter : public XMLVisitor
1408{
1409public:
1410 /** Construct the printer. If the FILE* is specified,
1411 this will print to the FILE. Else it will print
Lee Thomason4cd85342012-06-04 17:02:37 -07001412 to memory, and the result is available in CStr().
1413 If 'compact' is set to true, then output is created
1414 with only required whitespace and newlines.
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001415 */
sniperbat25900882012-05-28 17:22:07 +08001416 XMLPrinter( FILE* file=0, bool compact = false );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001417 ~XMLPrinter() {}
1418
1419 /** If streaming, write the BOM and declaration. */
1420 void PushHeader( bool writeBOM, bool writeDeclaration );
1421 /** If streaming, start writing an element.
1422 The element must be closed with CloseElement()
1423 */
1424 void OpenElement( const char* name );
1425 /// If streaming, add an attribute to an open element.
1426 void PushAttribute( const char* name, const char* value );
1427 void PushAttribute( const char* name, int value );
1428 void PushAttribute( const char* name, unsigned value );
1429 void PushAttribute( const char* name, bool value );
1430 void PushAttribute( const char* name, double value );
1431 /// If streaming, close the Element.
1432 void CloseElement();
1433
1434 /// Add a text node.
1435 void PushText( const char* text, bool cdata=false );
Lee Thomason21be8822012-07-15 17:27:22 -07001436 /// Add a text node from an integer.
1437 void PushText( int value );
1438 /// Add a text node from an unsigned.
1439 void PushText( unsigned value );
1440 /// Add a text node from a bool.
1441 void PushText( bool value );
1442 /// Add a text node from a float.
1443 void PushText( float value );
1444 /// Add a text node from a double.
1445 void PushText( double value );
1446
1447 /// Add a comment
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001448 void PushComment( const char* comment );
1449
1450 void PushDeclaration( const char* value );
1451 void PushUnknown( const char* value );
1452
1453 virtual bool VisitEnter( const XMLDocument& /*doc*/ );
1454 virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
1455
1456 virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute );
1457 virtual bool VisitExit( const XMLElement& element );
1458
1459 virtual bool Visit( const XMLText& text );
1460 virtual bool Visit( const XMLComment& comment );
1461 virtual bool Visit( const XMLDeclaration& declaration );
1462 virtual bool Visit( const XMLUnknown& unknown );
1463
1464 /**
1465 If in print to memory mode, return a pointer to
1466 the XML file in memory.
1467 */
1468 const char* CStr() const { return buffer.Mem(); }
sniperbate01e7862012-05-21 12:45:36 +08001469 /**
Lee Thomason (grinliz)2f1f6242012-09-16 11:32:34 -07001470 If in print to memory mode, return the size
Lee Thomason (grinliz)48ea0bc2012-05-26 14:41:14 -07001471 of the XML file in memory. (Note the size returned
1472 includes the terminating null.)
sniperbate01e7862012-05-21 12:45:36 +08001473 */
Lee Thomasonc78dc012012-06-12 13:12:15 -07001474 int CStrSize() const { return buffer.Size(); }
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001475
1476private:
Lee Thomason7d00b9a2012-02-27 17:54:22 -08001477 void SealElement();
1478 void PrintSpace( int depth );
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001479 void PrintString( const char*, bool restrictedEntitySet ); // prints out, after detecting entities.
1480 void Print( const char* format, ... );
1481
1482 bool elementJustOpened;
1483 bool firstElement;
1484 FILE* fp;
1485 int depth;
1486 int textDepth;
1487 bool processEntities;
sniperbat25900882012-05-28 17:22:07 +08001488 bool compactMode;
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001489
1490 enum {
1491 ENTITY_RANGE = 64,
1492 BUF_SIZE = 200
1493 };
1494 bool entityFlag[ENTITY_RANGE];
1495 bool restrictedEntityFlag[ENTITY_RANGE];
1496
1497 DynArray< const char*, 10 > stack;
PKEuSe736f292012-07-16 03:27:55 -07001498 DynArray< char, 20 > buffer;
1499#ifdef _MSC_VER
1500 DynArray< char, 20 > accumulator;
1501#endif
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001502};
1503
1504
Guillermo A. Amaralb42ba362012-03-20 00:15:30 -07001505} // tinyxml2
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001506
1507
U-Lama\Leee13c3e62011-12-28 14:36:55 -08001508#endif // TINYXML2_INCLUDED