added a bunch of comments in

This commit is contained in:
Lee Thomason (grinliz) 2012-02-24 17:37:53 -08:00
parent 784607f31d
commit 2a1cd27732
3 changed files with 390 additions and 117 deletions

View File

@ -448,7 +448,7 @@ XMLNode::XMLNode( XMLDocument* doc ) :
XMLNode::~XMLNode() XMLNode::~XMLNode()
{ {
ClearChildren(); DeleteChildren();
if ( parent ) { if ( parent ) {
parent->Unlink( this ); parent->Unlink( this );
} }
@ -464,7 +464,7 @@ void XMLNode::SetValue( const char* str, bool staticMem )
} }
void XMLNode::ClearChildren() void XMLNode::DeleteChildren()
{ {
while( firstChild ) { while( firstChild ) {
XMLNode* node = firstChild; XMLNode* node = firstChild;
@ -1106,7 +1106,7 @@ XMLDocument::XMLDocument() :
XMLDocument::~XMLDocument() XMLDocument::~XMLDocument()
{ {
ClearChildren(); DeleteChildren();
delete [] charBuffer; delete [] charBuffer;
#if 0 #if 0
@ -1164,7 +1164,7 @@ XMLText* XMLDocument::NewText( const char* str )
int XMLDocument::LoadFile( const char* filename ) int XMLDocument::LoadFile( const char* filename )
{ {
ClearChildren(); DeleteChildren();
InitDocument(); InitDocument();
FILE* fp = fopen( filename, "rb" ); FILE* fp = fopen( filename, "rb" );
@ -1180,7 +1180,7 @@ int XMLDocument::LoadFile( const char* filename )
int XMLDocument::LoadFile( FILE* fp ) int XMLDocument::LoadFile( FILE* fp )
{ {
ClearChildren(); DeleteChildren();
InitDocument(); InitDocument();
fseek( fp, 0, SEEK_END ); fseek( fp, 0, SEEK_END );
@ -1211,7 +1211,7 @@ int XMLDocument::LoadFile( FILE* fp )
void XMLDocument::SaveFile( const char* filename ) void XMLDocument::SaveFile( const char* filename )
{ {
FILE* fp = fopen( filename, "w" ); FILE* fp = fopen( filename, "w" );
XMLStreamer stream( fp ); XMLPrinter stream( fp );
Print( &stream ); Print( &stream );
fclose( fp ); fclose( fp );
} }
@ -1219,7 +1219,7 @@ void XMLDocument::SaveFile( const char* filename )
int XMLDocument::Parse( const char* p ) int XMLDocument::Parse( const char* p )
{ {
ClearChildren(); DeleteChildren();
InitDocument(); InitDocument();
if ( !p || !*p ) { if ( !p || !*p ) {
@ -1243,9 +1243,9 @@ int XMLDocument::Parse( const char* p )
} }
void XMLDocument::Print( XMLStreamer* streamer ) void XMLDocument::Print( XMLPrinter* streamer )
{ {
XMLStreamer stdStreamer( stdout ); XMLPrinter stdStreamer( stdout );
if ( !streamer ) if ( !streamer )
streamer = &stdStreamer; streamer = &stdStreamer;
Accept( streamer ); Accept( streamer );
@ -1281,7 +1281,7 @@ void XMLDocument::PrintError() const
} }
XMLStreamer::XMLStreamer( FILE* file ) : XMLPrinter::XMLPrinter( FILE* file ) :
elementJustOpened( false ), elementJustOpened( false ),
firstElement( true ), firstElement( true ),
fp( file ), fp( file ),
@ -1305,7 +1305,7 @@ XMLStreamer::XMLStreamer( FILE* file ) :
} }
void XMLStreamer::Print( const char* format, ... ) void XMLPrinter::Print( const char* format, ... )
{ {
va_list va; va_list va;
va_start( va, format ); va_start( va, format );
@ -1338,7 +1338,7 @@ void XMLStreamer::Print( const char* format, ... )
} }
void XMLStreamer::PrintSpace( int depth ) void XMLPrinter::PrintSpace( int depth )
{ {
for( int i=0; i<depth; ++i ) { for( int i=0; i<depth; ++i ) {
Print( " " ); Print( " " );
@ -1346,7 +1346,7 @@ void XMLStreamer::PrintSpace( int depth )
} }
void XMLStreamer::PrintString( const char* p, bool restricted ) void XMLPrinter::PrintString( const char* p, bool restricted )
{ {
// Look for runs of bytes between entities to print. // Look for runs of bytes between entities to print.
const char* q = p; const char* q = p;
@ -1382,7 +1382,7 @@ void XMLStreamer::PrintString( const char* p, bool restricted )
} }
void XMLStreamer::PushHeader( bool writeBOM, bool writeDec ) void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
{ {
static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 }; static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
if ( writeBOM ) { if ( writeBOM ) {
@ -1394,7 +1394,7 @@ void XMLStreamer::PushHeader( bool writeBOM, bool writeDec )
} }
void XMLStreamer::OpenElement( const char* name ) void XMLPrinter::OpenElement( const char* name )
{ {
if ( elementJustOpened ) { if ( elementJustOpened ) {
SealElement(); SealElement();
@ -1413,7 +1413,7 @@ void XMLStreamer::OpenElement( const char* name )
} }
void XMLStreamer::PushAttribute( const char* name, const char* value ) void XMLPrinter::PushAttribute( const char* name, const char* value )
{ {
TIXMLASSERT( elementJustOpened ); TIXMLASSERT( elementJustOpened );
Print( " %s=\"", name ); Print( " %s=\"", name );
@ -1422,7 +1422,7 @@ void XMLStreamer::PushAttribute( const char* name, const char* value )
} }
void XMLStreamer::CloseElement() void XMLPrinter::CloseElement()
{ {
--depth; --depth;
const char* name = stack.Pop(); const char* name = stack.Pop();
@ -1446,14 +1446,14 @@ void XMLStreamer::CloseElement()
} }
void XMLStreamer::SealElement() void XMLPrinter::SealElement()
{ {
elementJustOpened = false; elementJustOpened = false;
Print( ">" ); Print( ">" );
} }
void XMLStreamer::PushText( const char* text, bool cdata ) void XMLPrinter::PushText( const char* text, bool cdata )
{ {
textDepth = depth-1; textDepth = depth-1;
@ -1471,7 +1471,7 @@ void XMLStreamer::PushText( const char* text, bool cdata )
} }
void XMLStreamer::PushComment( const char* comment ) void XMLPrinter::PushComment( const char* comment )
{ {
if ( elementJustOpened ) { if ( elementJustOpened ) {
SealElement(); SealElement();
@ -1485,7 +1485,7 @@ void XMLStreamer::PushComment( const char* comment )
} }
void XMLStreamer::PushDeclaration( const char* value ) void XMLPrinter::PushDeclaration( const char* value )
{ {
if ( elementJustOpened ) { if ( elementJustOpened ) {
SealElement(); SealElement();
@ -1499,7 +1499,7 @@ void XMLStreamer::PushDeclaration( const char* value )
} }
void XMLStreamer::PushUnknown( const char* value ) void XMLPrinter::PushUnknown( const char* value )
{ {
if ( elementJustOpened ) { if ( elementJustOpened ) {
SealElement(); SealElement();
@ -1513,7 +1513,7 @@ void XMLStreamer::PushUnknown( const char* value )
} }
bool XMLStreamer::VisitEnter( const XMLDocument& doc ) bool XMLPrinter::VisitEnter( const XMLDocument& doc )
{ {
if ( doc.HasBOM() ) { if ( doc.HasBOM() ) {
PushHeader( true, false ); PushHeader( true, false );
@ -1522,7 +1522,7 @@ bool XMLStreamer::VisitEnter( const XMLDocument& doc )
} }
bool XMLStreamer::VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
{ {
OpenElement( element.Name() ); OpenElement( element.Name() );
while ( attribute ) { while ( attribute ) {
@ -1533,34 +1533,34 @@ bool XMLStreamer::VisitEnter( const XMLElement& element, const XMLAttribute* att
} }
bool XMLStreamer::VisitExit( const XMLElement& element ) bool XMLPrinter::VisitExit( const XMLElement& element )
{ {
CloseElement(); CloseElement();
return true; return true;
} }
bool XMLStreamer::Visit( const XMLText& text ) bool XMLPrinter::Visit( const XMLText& text )
{ {
PushText( text.Value(), text.CData() ); PushText( text.Value(), text.CData() );
return true; return true;
} }
bool XMLStreamer::Visit( const XMLComment& comment ) bool XMLPrinter::Visit( const XMLComment& comment )
{ {
PushComment( comment.Value() ); PushComment( comment.Value() );
return true; return true;
} }
bool XMLStreamer::Visit( const XMLDeclaration& declaration ) bool XMLPrinter::Visit( const XMLDeclaration& declaration )
{ {
PushDeclaration( declaration.Value() ); PushDeclaration( declaration.Value() );
return true; return true;
} }
bool XMLStreamer::Visit( const XMLUnknown& unknown ) bool XMLPrinter::Visit( const XMLUnknown& unknown )
{ {
PushUnknown( unknown.Value() ); PushUnknown( unknown.Value() );
return true; return true;

View File

@ -1,36 +1,16 @@
#ifndef TINYXML_INCLUDED #ifndef TINYXML_INCLUDED
#define TINYXML2_INCLUDED #define TINYXML2_INCLUDED
/*
TODO
X const and non-const versions of API
X memory pool the class construction
X attribute accessors
X node navigation
- handles
X visit pattern - change streamer?
X make constructors protected
X hide copy constructor
X hide = operator
X UTF8 support: isAlpha, etc.
X string buffer for sets. (Grr.)
- MS BOM
X print to memory buffer
- tests from xml1
- xml1 tests especially UTF-8
- perf test: xml1
- perf test: xenowar
- test: load(char*)
- test: load(FILE*)
- rename declaration
- rename streamer
*/
#include <limits.h> #include <limits.h>
#include <ctype.h> #include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include <memory.h> #include <memory.h>
/* TODO: create main page description.
TODO: add 'lastAttribute' for faster parsing.
*/
#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__) #if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
#ifndef DEBUG #ifndef DEBUG
#define DEBUG #define DEBUG
@ -89,12 +69,12 @@ class XMLText;
class XMLDeclaration; class XMLDeclaration;
class XMLUnknown; class XMLUnknown;
class XMLStreamer; class XMLPrinter;
/* /*
A class that wraps strings. Normally stores the start and end A class that wraps strings. Normally stores the start and end
pointers into the XML file itself, and will apply normalization pointers into the XML file itself, and will apply normalization
and entity transalion if actually read. Can also store (and memory and entity translation if actually read. Can also store (and memory
manage) a traditional char[] manage) a traditional char[]
*/ */
class StrPair class StrPair
@ -380,20 +360,48 @@ public:
}; };
/** XMLNode is a base class for every object that is in the
XML Document Object Model (DOM), except XMLAttributes.
Nodes have siblings, a parent, and children which can
be navigated. A node is always in a XMLDocument.
The type of a TiXmlNode can be queried, and it can
be cast to its more defined type.
An XMLDocument allocates memory for all its Nodes.
When the XMLDocument gets deleted, all its Nodes
will also be deleted.
@verbatim
A Document can contain: Element (container or leaf)
Comment (leaf)
Unknown (leaf)
Declaration( leaf )
An Element can contain: Element (container or leaf)
Text (leaf)
Attributes (not on tree)
Comment (leaf)
Unknown (leaf)
@endverbatim
*/
class XMLNode class XMLNode
{ {
friend class XMLDocument; friend class XMLDocument;
friend class XMLElement; friend class XMLElement;
public: public:
/// Get the XMLDocument that owns this XMLNode.
const XMLDocument* GetDocument() const { return document; } const XMLDocument* GetDocument() const { return document; }
/// Get the XMLDocument that owns this XMLNode.
XMLDocument* GetDocument() { return document; } XMLDocument* GetDocument() { return document; }
virtual XMLElement* ToElement() { return 0; } virtual XMLElement* ToElement() { return 0; } ///< Safely cast to an Element, or null.
virtual XMLText* ToText() { return 0; } virtual XMLText* ToText() { return 0; } ///< Safely cast to Text, or null.
virtual XMLComment* ToComment() { return 0; } virtual XMLComment* ToComment() { return 0; } ///< Safely cast to a Comment, or null.
virtual XMLDocument* ToDocument() { return 0; } virtual XMLDocument* ToDocument() { return 0; } ///< Safely cast to a Document, or null.
virtual XMLDeclaration* ToDeclaration() { return 0; } virtual XMLDeclaration* ToDeclaration() { return 0; } ///< Safely cast to a Declaration, or null.
virtual XMLUnknown* ToUnknown() { return 0; } virtual XMLUnknown* ToUnknown() { return 0; } ///< Safely cast to an Unknown, or null.
virtual const XMLElement* ToElement() const { return 0; } virtual const XMLElement* ToElement() const { return 0; }
virtual const XMLText* ToText() const { return 0; } virtual const XMLText* ToText() const { return 0; }
@ -402,66 +410,111 @@ public:
virtual const XMLDeclaration* ToDeclaration() const { return 0; } virtual const XMLDeclaration* ToDeclaration() const { return 0; }
virtual const XMLUnknown* ToUnknown() const { return 0; } virtual const XMLUnknown* ToUnknown() const { return 0; }
/** The meaning of 'value' changes for the specific type.
@verbatim
Document: empy
Element: name of the element
Comment: the comment text
Unknown: the tag contents
Text: the text string
@endverbatim
*/
const char* Value() const { return value.GetStr(); } const char* Value() const { return value.GetStr(); }
/** Set the Value of an XML node.
@sa Value()
*/
void SetValue( const char* val, bool staticMem=false ); void SetValue( const char* val, bool staticMem=false );
/// Get the parent of this node on the DOM.
const XMLNode* Parent() const { return parent; } const XMLNode* Parent() const { return parent; }
XMLNode* Parent() { return parent; } XMLNode* Parent() { return parent; }
/// Returns true if this node has no children. /// Returns true if this node has no children.
bool NoChildren() const { return !firstChild; } bool NoChildren() const { return !firstChild; }
/// Get the first child node, or null if none exists.
const XMLNode* FirstChild() const { return firstChild; } const XMLNode* FirstChild() const { return firstChild; }
XMLNode* FirstChild() { return firstChild; } XMLNode* FirstChild() { return firstChild; }
/** Get the first child element, or optionally the first child
element with the specified name.
*/
const XMLElement* FirstChildElement( const char* value=0 ) const; const XMLElement* FirstChildElement( const char* value=0 ) const;
XMLElement* FirstChildElement( const char* value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( value )); } XMLElement* FirstChildElement( const char* value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( value )); }
/// Get the last child node, or null if none exists.
const XMLNode* LastChild() const { return lastChild; } const XMLNode* LastChild() const { return lastChild; }
XMLNode* LastChild() { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); } XMLNode* LastChild() { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); }
/** Get the last child element or optionally the last child
element with the specified name.
*/
const XMLElement* LastChildElement( const char* value=0 ) const; const XMLElement* LastChildElement( const char* value=0 ) const;
XMLElement* LastChildElement( const char* value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(value) ); } XMLElement* LastChildElement( const char* value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(value) ); }
/// Get the previous (left) sibling node of this node.
const XMLNode* PreviousSibling() const { return prev; } const XMLNode* PreviousSibling() const { return prev; }
XMLNode* PreviousSibling() { return prev; } XMLNode* PreviousSibling() { return prev; }
/// Get the previous (left) sibling element of this node, with an opitionally supplied name.
const XMLNode* PreviousSiblingElement( const char* value=0 ) const ; const XMLNode* PreviousSiblingElement( const char* value=0 ) const ;
XMLNode* PreviousSiblingElement( const char* value=0 ) { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( value ) ); } XMLNode* PreviousSiblingElement( const char* value=0 ) { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( value ) ); }
/// Get the next (right) sibling node of this node.
const XMLNode* NextSibling() const { return next; } const XMLNode* NextSibling() const { return next; }
XMLNode* NextSibling() { return next; } XMLNode* NextSibling() { return next; }
/// Get the next (right) sibling element of this node, with an opitionally supplied name.
const XMLNode* NextSiblingElement( const char* value=0 ) const; const XMLNode* NextSiblingElement( const char* value=0 ) const;
XMLNode* NextSiblingElement( const char* value=0 ) { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->NextSiblingElement( value ) ); } XMLNode* NextSiblingElement( const char* value=0 ) { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->NextSiblingElement( value ) ); }
/** /**
Add a child node as the last (right) child.
Tests: Programmatic DOM
*/ */
XMLNode* InsertEndChild( XMLNode* addThis ); XMLNode* InsertEndChild( XMLNode* addThis );
/** /**
Add a child node as the first (left) child.
Tests: Programmatic DOM
*/ */
XMLNode* InsertFirstChild( XMLNode* addThis ); XMLNode* InsertFirstChild( XMLNode* addThis );
/** /**
Add a node after the specified child node.
Tests: Programmatic DOM
*/ */
XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
/** /**
Tests: All (used by destructor) Delete all the children of this node.
*/ */
void ClearChildren(); void DeleteChildren();
/** /**
Tests: Progammatic DOM Delete a child of this node.
*/ */
void DeleteChild( XMLNode* node ); void DeleteChild( XMLNode* node );
/** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the
XML tree will be conditionally visited and the host will be called back
via the TiXmlVisitor interface.
This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
the XML for the callbacks, so the performance of TinyXML is unchanged by using this
interface versus any other.)
The interface has been based on ideas from:
- http://www.saxproject.org/
- http://c2.com/cgi/wiki?HierarchicalVisitorPattern
Which are both good references for "visiting".
An example of using Accept():
@verbatim
TiXmlPrinter printer;
tinyxmlDoc.Accept( &printer );
const char* xmlcstr = printer.CStr();
@endverbatim
*/
virtual bool Accept( XMLVisitor* visitor ) const = 0; virtual bool Accept( XMLVisitor* visitor ) const = 0;
// internal
virtual char* ParseDeep( char*, StrPair* ); virtual char* ParseDeep( char*, StrPair* );
protected: protected:
@ -486,6 +539,18 @@ private:
}; };
/** XML text.
Note that a text node can have child element nodes, for example:
@verbatim
<root>This is <b>bold</b></root>
@endverbatim
A text node can have 2 ways to output the next. "normal" output
and CDATA. It will default to the mode it was parsed from the XML file and
you generally want to leave it alone, but you can change the output mode with
SetCDATA() and query it with CDATA().
*/
class XMLText : public XMLNode class XMLText : public XMLNode
{ {
friend class XMLBase; friend class XMLBase;
@ -496,7 +561,9 @@ public:
virtual XMLText* ToText() { return this; } virtual XMLText* ToText() { return this; }
virtual const XMLText* ToText() const { return this; } virtual const XMLText* ToText() const { return this; }
void SetCData( bool value ) { isCData = true; } /// Declare whether this should be CDATA or standard text.
void SetCData( bool isCData ) { this->isCData = isCData; }
/// Returns true if this is a CDATA text element.
bool CData() const { return isCData; } bool CData() const { return isCData; }
char* ParseDeep( char*, StrPair* endTag ); char* ParseDeep( char*, StrPair* endTag );
@ -512,6 +579,7 @@ private:
}; };
/** An XML Comment. */
class XMLComment : public XMLNode class XMLComment : public XMLNode
{ {
friend class XMLDocument; friend class XMLDocument;
@ -533,6 +601,17 @@ private:
}; };
/** In correct XML the declaration is the first entry in the file.
@verbatim
<?xml version="1.0" standalone="yes"?>
@endverbatim
TinyXML2 will happily read or write files without a declaration,
however.
The text of the declaration isn't interpreted. It is parsed
and written as a string.
*/
class XMLDeclaration : public XMLNode class XMLDeclaration : public XMLNode
{ {
friend class XMLDocument; friend class XMLDocument;
@ -552,6 +631,13 @@ protected:
}; };
/** Any tag that tinyXml doesn't recognize is saved as an
unknown. It is a tag of text, but should not be modified.
It will be written back to the XML, unchanged, when the file
is saved.
DTD tags get thrown into TiXmlUnknowns.
*/
class XMLUnknown : public XMLNode class XMLUnknown : public XMLNode
{ {
friend class XMLDocument; friend class XMLDocument;
@ -593,31 +679,59 @@ enum {
}; };
/** An attribute is a name-value pair. Elements have an arbitrary
number of attributes, each with a unique name.
@note The attributes are not XMLNodes. You may only query the
Next() attribute in a list.
*/
class XMLAttribute class XMLAttribute
{ {
friend class XMLElement; friend class XMLElement;
public: public:
const char* Name() const { return name.GetStr(); } const char* Name() const { return name.GetStr(); } ///< The name of the attribute.
const char* Value() const { return value.GetStr(); } const char* Value() const { return value.GetStr(); } ///< The value of the attribute.
const XMLAttribute* Next() const { return next; } const XMLAttribute* Next() const { return next; } ///< The next attribute in the list.
/** IntAttribute interprets the attribute as an integer, and returns the value.
If the value isn't an integer, 0 will be returned. There is no error checking;
use QueryIntAttribute() if you need error checking.
*/
int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( &i ); return i; } int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( &i ); return i; }
/// Query as an unsigned integer. See IntAttribute()
unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( &i ); return i; } unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( &i ); return i; }
/// Query as a boolean. See IntAttribute()
bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( &b ); return b; } bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( &b ); return b; }
/// Query as a double. See IntAttribute()
double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( &d ); return d; } double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( &d ); return d; }
/// Query as a float. See IntAttribute()
float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( &f ); return f; } float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( &f ); return f; }
/** QueryIntAttribute interprets the attribute as an integer, and returns the value
in the provided paremeter. The function will return XML_NO_ERROR on success,
and WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
*/
int QueryIntAttribute( int* value ) const; int QueryIntAttribute( int* value ) const;
/// See QueryIntAttribute
int QueryUnsignedAttribute( unsigned int* value ) const; int QueryUnsignedAttribute( unsigned int* value ) const;
/// See QueryIntAttribute
int QueryBoolAttribute( bool* value ) const; int QueryBoolAttribute( bool* value ) const;
/// See QueryIntAttribute
int QueryDoubleAttribute( double* value ) const; int QueryDoubleAttribute( double* value ) const;
/// See QueryIntAttribute
int QueryFloatAttribute( float* value ) const; int QueryFloatAttribute( float* value ) const;
/// Set the attribute to a string value.
void SetAttribute( const char* value ); void SetAttribute( const char* value );
/// Set the attribute to value.
void SetAttribute( int value ); void SetAttribute( int value );
/// Set the attribute to value.
void SetAttribute( unsigned value ); void SetAttribute( unsigned value );
/// Set the attribute to value.
void SetAttribute( bool value ); void SetAttribute( bool value );
/// Set the attribute to value.
void SetAttribute( double value ); void SetAttribute( double value );
/// Set the attribute to value.
void SetAttribute( float value ); void SetAttribute( float value );
private: private:
@ -638,46 +752,116 @@ private:
}; };
/** The element is a container class. It has a value, the element name,
and can contain other elements, text, comments, and unknowns.
Elements also contain an arbitrary number of attributes.
*/
class XMLElement : public XMLNode class XMLElement : public XMLNode
{ {
friend class XMLBase; friend class XMLBase;
friend class XMLDocument; friend class XMLDocument;
public: public:
/// Get the name of an element (which is the Value() of the node.)
const char* Name() const { return Value(); } const char* Name() const { return Value(); }
/// Set the name of the element.
void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); } void SetName( const char* str, bool staticMem=false ) { SetValue( str, staticMem ); }
virtual XMLElement* ToElement() { return this; } virtual XMLElement* ToElement() { return this; }
virtual const XMLElement* ToElement() const { return this; } virtual const XMLElement* ToElement() const { return this; }
virtual bool Accept( XMLVisitor* visitor ) const; virtual bool Accept( XMLVisitor* visitor ) const;
/** Given an attribute name, Attribute() returns the value
for the attribute of that name, or null if none exists.
*/
const char* Attribute( const char* name ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return 0; return a->Value(); } const char* Attribute( const char* name ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return 0; return a->Value(); }
/** Given an attribute name, IntAttribute() returns the value
of the attribute interpreted as an integer. 0 will be
returned if there is an error. For a method with error
checking, see QueryIntAttribute()
*/
int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( name, &i ); return i; } int IntAttribute( const char* name ) const { int i=0; QueryIntAttribute( name, &i ); return i; }
/// See IntAttribute()
unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( name, &i ); return i; } unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( name, &i ); return i; }
/// See IntAttribute()
bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( name, &b ); return b; } bool BoolAttribute( const char* name ) const { bool b=false; QueryBoolAttribute( name, &b ); return b; }
/// See IntAttribute()
double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( name, &d ); return d; } double DoubleAttribute( const char* name ) const { double d=0; QueryDoubleAttribute( name, &d ); return d; }
/// See IntAttribute()
float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( name, &f ); return f; } float FloatAttribute( const char* name ) const { float f=0; QueryFloatAttribute( name, &f ); return f; }
/** Given an attribute name, QueryIntAttribute() returns
XML_NO_ERROR, WRONG_ATTRIBUTE_TYPE if the conversion
can't be performed, or NO_ATTRIBUTE if the attribute
doesn't exist. If successful, the result of the conversion
will be written to 'value'. If not successful, nothing will
be written to 'value'. This allows you to provide default
value:
@verbatim
int value = 10;
QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
@endverbatim
*/
int QueryIntAttribute( const char* name, int* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryIntAttribute( value ); } int QueryIntAttribute( const char* name, int* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryIntAttribute( value ); }
/// See QueryIntAttribute()
int QueryUnsignedAttribute( const char* name, unsigned int* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryUnsignedAttribute( value ); } int QueryUnsignedAttribute( const char* name, unsigned int* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryUnsignedAttribute( value ); }
/// See QueryIntAttribute()
int QueryBoolAttribute( const char* name, bool* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryBoolAttribute( value ); } int QueryBoolAttribute( const char* name, bool* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryBoolAttribute( value ); }
/// See QueryIntAttribute()
int QueryDoubleAttribute( const char* name, double* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryDoubleAttribute( value ); } int QueryDoubleAttribute( const char* name, double* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryDoubleAttribute( value ); }
/// See QueryIntAttribute()
int QueryFloatAttribute( const char* name, float* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryFloatAttribute( value ); } int QueryFloatAttribute( const char* name, float* value ) const { const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryFloatAttribute( value ); }
/// Sets the named attribute to value.
void SetAttribute( const char* name, const char* value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } void SetAttribute( const char* name, const char* value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
/// Sets the named attribute to value.
void SetAttribute( const char* name, int value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } void SetAttribute( const char* name, int value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
/// Sets the named attribute to value.
void SetAttribute( const char* name, unsigned value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } void SetAttribute( const char* name, unsigned value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
/// Sets the named attribute to value.
void SetAttribute( const char* name, bool value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } void SetAttribute( const char* name, bool value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
/// Sets the named attribute to value.
void SetAttribute( const char* name, double value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } void SetAttribute( const char* name, double value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
/** /**
Tests: Programmatic DOM Delete an attribute.
*/ */
void DeleteAttribute( const char* name ); void DeleteAttribute( const char* name );
/// Return the first attribute in the list.
const XMLAttribute* FirstAttribute() const { return rootAttribute; } const XMLAttribute* FirstAttribute() const { return rootAttribute; }
/// Query a specific attribute in the list.
const XMLAttribute* FindAttribute( const char* name ) const; const XMLAttribute* FindAttribute( const char* name ) const;
/** Convenience function for easy access to the text inside an element. Although easy
and concise, GetText() is limited compared to getting the TiXmlText child
and accessing it directly.
If the first child of 'this' is a TiXmlText, the GetText()
returns the character string of the Text node, else null is returned.
This is a convenient method for getting the text of simple contained text:
@verbatim
<foo>This is text</foo>
const char* str = fooElement->GetText();
@endverbatim
'str' will be a pointer to "This is text".
Note that this function can be misleading. If the element foo was created from
this XML:
@verbatim
<foo><b>This is text</b></foo>
@endverbatim
then the value of str would be null. The first child node isn't a text node, it is
another element. From this XML:
@verbatim
<foo>This is <b>text</b></foo>
@endverbatim
GetText() will return "This is ".
*/
const char* GetText() const; const char* GetText() const;
// internal: // internal:
@ -705,54 +889,111 @@ private:
}; };
/** A document binds together all the functionality.
It can be saved, loaded, and printed to the screen.
All Nodes are connected and allocated to a Document.
If the Document is deleted, all its Nodes are also deleted.
*/
class XMLDocument : public XMLNode class XMLDocument : public XMLNode
{ {
friend class XMLElement; friend class XMLElement;
public: public:
/// constructor
XMLDocument(); XMLDocument();
~XMLDocument(); ~XMLDocument();
virtual XMLDocument* ToDocument() { return this; } virtual XMLDocument* ToDocument() { return this; }
virtual const XMLDocument* ToDocument() const { return this; } virtual const XMLDocument* ToDocument() const { return this; }
/**
Parse an XML file from a character string.
Returns XML_NO_ERROR (0) on success, or
an errorID.
*/
int Parse( const char* xml ); int Parse( const char* xml );
/**
Load an XML file from disk.
Returns XML_NO_ERROR (0) on success, or
an errorID.
*/
int LoadFile( const char* filename ); int LoadFile( const char* filename );
/**
Load an XML file from disk. You are responsible
for providing and closing the FILE*.
Returns XML_NO_ERROR (0) on success, or
an errorID.
*/
int LoadFile( FILE* ); int LoadFile( FILE* );
/**
Save the XML file to disk.
*/
void SaveFile( const char* filename ); void SaveFile( const char* filename );
bool HasBOM() const { return writeBOM; } bool HasBOM() const { return writeBOM; }
/** Return the root element of DOM. Equivalent to FirstChildElement().
To get the first node, use FirstChild().
*/
XMLElement* RootElement() { return FirstChildElement(); } XMLElement* RootElement() { return FirstChildElement(); }
const XMLElement* RootElement() const { return FirstChildElement(); } const XMLElement* RootElement() const { return FirstChildElement(); }
void Print( XMLStreamer* streamer=0 ); /** Print the Document. If the Printer is not provided, it will
print to stdout. If you provide Printer, this can print to a file:
@verbatim
XMLPrinter printer( fp );
doc.Print( &printer );
@endverbatim
Or you can use a printer to print to memory:
@verbatim
XMLPrinter printer;
doc->Print( &printer );
SomeFunctior( printer.CStr() );
@endverbatim
*/
void Print( XMLPrinter* streamer=0 );
virtual bool Accept( XMLVisitor* visitor ) const; virtual bool Accept( XMLVisitor* visitor ) const;
/** /**
Tests: Programmatic DOM Create a new Element associated with
this Document. The memory for the Element
is managed by the Document.
*/ */
XMLElement* NewElement( const char* name ); XMLElement* NewElement( const char* name );
/** /**
Tests: Programmatic DOM Create a new Comment associated with
this Document. The memory for the Comment
is managed by the Document.
*/ */
XMLComment* NewComment( const char* comment ); XMLComment* NewComment( const char* comment );
/** /**
Tests: Programmatic DOM Create a new Text associated with
this Document. The memory for the Text
is managed by the Document.
*/ */
XMLText* NewText( const char* text ); XMLText* NewText( const char* text );
/** /**
Tests: Programmatic DOM Delete a node associated with this documented.
It will be unlinked from the DOM.
*/ */
void DeleteNode( XMLNode* node ) { node->parent->DeleteChild( node ); } void DeleteNode( XMLNode* node ) { node->parent->DeleteChild( node ); }
void SetError( int error, const char* str1, const char* str2 ); void SetError( int error, const char* str1, const char* str2 );
/// Return true if there was an error parsing the document.
bool Error() const { return errorID != XML_NO_ERROR; } bool Error() const { return errorID != XML_NO_ERROR; }
/// Return the errorID.
int ErrorID() const { return errorID; } int ErrorID() const { return errorID; }
/// Return a possibly helpful diagnostic location or string.
const char* GetErrorStr1() const { return errorStr1; } const char* GetErrorStr1() const { return errorStr1; }
/// Return possibly helpful secondary diagnostic location or string.
const char* GetErrorStr2() const { return errorStr2; } const char* GetErrorStr2() const { return errorStr2; }
/// If there is an error, print it to stdout
void PrintError() const; void PrintError() const;
// internal
char* Identify( char* p, XMLNode** node ); char* Identify( char* p, XMLNode** node );
private: private:
@ -773,19 +1014,75 @@ private:
}; };
class XMLStreamer : public XMLVisitor
/**
Printing functionality. The XMLPrinter gives you more
options than the XMLDocument::Print() method.
It can:
-# Print to memory.
-# Print to a file you provide
-# Print XML without a XMLDocument.
Print to Memory
@verbatim
XMLPrinter printer;
doc->Print( &printer );
SomeFunctior( printer.CStr() );
@endverbatim
Print to a File
You provide the file pointer.
@verbatim
XMLPrinter printer( fp );
doc.Print( &printer );
@endverbatim
Print without a XMLDocument
When loading, an XML parser is very useful. However, sometimes
when saving, it just gets in the way. The code is often set up
for streaming, and constructing the DOM is just overhead.
The Printer supports the streaming case. The following code
prints out a trivially simple XML file without ever creating
an XML document.
@verbatim
XMLPrinter printer( fp );
printer.OpenElement( "foo" );
printer.PushAttribute( "foo", "bar" );
printer.CloseElement();
@endverbatim
*/
class XMLPrinter : public XMLVisitor
{ {
public: public:
XMLStreamer( FILE* file=0 ); /** Construct the printer. If the FILE* is specified,
~XMLStreamer() {} this will print to the FILE. Else it will print
to memory, and the result is available in CStr()
*/
XMLPrinter( FILE* file=0 );
~XMLPrinter() {}
/** If streaming, write the BOM and declaration. */
void PushHeader( bool writeBOM, bool writeDeclaration ); void PushHeader( bool writeBOM, bool writeDeclaration );
/** If streaming, start writing an element.
The element must be closed with CloseElement()
*/
void OpenElement( const char* name ); void OpenElement( const char* name );
/// If streaming, add an attribute to an open element.
void PushAttribute( const char* name, const char* value ); void PushAttribute( const char* name, const char* value );
/// If streaming, close the Element.
void CloseElement(); void CloseElement();
/// Add a text node.
void PushText( const char* text, bool cdata=false ); void PushText( const char* text, bool cdata=false );
/// Add a comment
void PushComment( const char* comment ); void PushComment( const char* comment );
void PushDeclaration( const char* value ); void PushDeclaration( const char* value );
void PushUnknown( const char* value ); void PushUnknown( const char* value );
@ -800,6 +1097,10 @@ public:
virtual bool Visit( const XMLDeclaration& declaration ); virtual bool Visit( const XMLDeclaration& declaration );
virtual bool Visit( const XMLUnknown& unknown ); virtual bool Visit( const XMLUnknown& unknown );
/**
If in print to memory mode, return a pointer to
the XML file in memory.
*/
const char* CStr() const { return buffer.Mem(); } const char* CStr() const { return buffer.Mem(); }
private: private:

View File

@ -4,7 +4,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#if defined( WIN32 ) #if defined( _MSC_VER )
#include <crtdbg.h> #include <crtdbg.h>
_CrtMemState startMemState; _CrtMemState startMemState;
_CrtMemState endMemState; _CrtMemState endMemState;
@ -14,35 +14,6 @@ using namespace tinyxml2;
int gPass = 0; int gPass = 0;
int gFail = 0; int gFail = 0;
//#define DREAM_ONLY
/*
int gNew = 0;
int gNewTotal = 0;
void* operator new( size_t size )
{
++gNew;
return malloc( size );
}
void* operator new[]( size_t size )
{
++gNew;
return malloc( size );
}
void operator delete[]( void* mem )
{
free( mem );
}
void operator delete( void* mem )
{
free( mem );
}
*/
bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true ) bool XMLTest (const char* testString, const char* expected, const char* found, bool echo=true )
{ {
@ -100,7 +71,7 @@ void NullLineEndings( char* p )
int main( int argc, const char* argv ) int main( int argc, const char* argv )
{ {
#if defined( WIN32 ) #if defined( _MSC_VER )
_CrtMemCheckpoint( &startMemState ); _CrtMemCheckpoint( &startMemState );
#endif #endif
@ -201,7 +172,7 @@ int main( int argc, const char* argv )
doc->Print(); doc->Print();
XMLStreamer streamer; XMLPrinter streamer;
doc->Print( &streamer ); doc->Print( &streamer );
printf( "%s", streamer.CStr() ); printf( "%s", streamer.CStr() );
@ -447,7 +418,7 @@ int main( int argc, const char* argv )
FILE* textfile = fopen( "textfile.txt", "w" ); FILE* textfile = fopen( "textfile.txt", "w" );
if ( textfile ) if ( textfile )
{ {
XMLStreamer streamer( textfile ); XMLPrinter streamer( textfile );
psg->Accept( &streamer ); psg->Accept( &streamer );
fclose( textfile ); fclose( textfile );
} }
@ -637,7 +608,8 @@ int main( int argc, const char* argv )
XMLTest( "Infinite loop test.", true, true ); XMLTest( "Infinite loop test.", true, true );
} }
#endif #endif
#if defined( WIN32 )
#if defined( _MSC_VER )
_CrtMemCheckpoint( &endMemState ); _CrtMemCheckpoint( &endMemState );
//_CrtMemDumpStatistics( &endMemState ); //_CrtMemDumpStatistics( &endMemState );