improved the streamer interface so it doesn't require text parent. now possible to connect visitor and streamer.
diff --git a/tinyxml2.cpp b/tinyxml2.cpp
index fd11c27..72f9db8 100644
--- a/tinyxml2.cpp
+++ b/tinyxml2.cpp
@@ -128,9 +128,9 @@
 */

 

 

-// --------- XMLBase ----------- //

+// --------- XMLUtil ----------- //

 

-char* XMLBase::ParseText( char* p, StrPair* pair, const char* endTag, int strFlags )

+char* StrPair::ParseText( char* p, const char* endTag, int strFlags )

 {

 	TIXMLASSERT( endTag && *endTag );

 

@@ -141,7 +141,7 @@
 	// Inner loop of text parsing.

 	while ( *p ) {

 		if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {

-			pair->Set( start, p, strFlags );

+			Set( start, p, strFlags );

 			return p + length;

 		}

 		++p;

@@ -150,7 +150,7 @@
 }

 

 

-char* XMLBase::ParseName( char* p, StrPair* pair )

+char* StrPair::ParseName( char* p )

 {

 	char* start = p;

 

@@ -159,12 +159,12 @@
 		return 0;

 	}

 

-	if ( !IsAlpha( *p ) ) {

+	if ( !XMLUtil::IsAlpha( *p ) ) {

 		return 0;

 	}

 

 	while( *p && (

-			   IsAlphaNum( (unsigned char) *p ) 

+			   XMLUtil::IsAlphaNum( (unsigned char) *p ) 

 			|| *p == '_'

 			|| *p == '-'

 			|| *p == '.'

@@ -174,7 +174,7 @@
 	}

 

 	if ( p > start ) {

-		pair->Set( start, p, 0 );

+		Set( start, p, 0 );

 		return p;

 	}

 	return 0;

@@ -185,7 +185,7 @@
 {

 	XMLNode* returnNode = 0;

 	char* start = p;

-	p = XMLBase::SkipWhiteSpace( p );

+	p = XMLUtil::SkipWhiteSpace( p );

 	if( !p || !*p )

 	{

 		return 0;

@@ -210,18 +210,18 @@
 	static const int cdataHeaderLen		= 9;

 	static const int elementHeaderLen	= 1;

 

-	if ( XMLBase::StringEqual( p, commentHeader, commentHeaderLen ) ) {

+	if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {

 		returnNode = new (commentPool.Alloc()) XMLComment( this );

 		returnNode->memPool = &commentPool;

 		p += commentHeaderLen;

 	}

-	else if ( XMLBase::StringEqual( p, elementHeader, elementHeaderLen ) ) {

+	else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {

 		returnNode = new (elementPool.Alloc()) XMLElement( this );

 		returnNode->memPool = &elementPool;

 		p += elementHeaderLen;

 	}

 	// fixme: better text detection

-	else if ( (*p != '<') && XMLBase::IsAlphaNum( *p ) ) {

+	else if ( (*p != '<') && XMLUtil::IsAlphaNum( *p ) ) {

 		returnNode = new (textPool.Alloc()) XMLText( this );

 		returnNode->memPool = &textPool;

 		p = start;	// Back it up, all the text counts.

@@ -235,6 +235,20 @@
 }

 

 

+bool XMLDocument::Accept( XMLVisitor* visitor ) const
+{
+	if ( visitor->VisitEnter( *this ) )
+	{
+		for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
+		{
+			if ( !node->Accept( visitor ) )
+				break;
+		}
+	}
+	return visitor->VisitExit( *this );
+}
+

+

 // --------- XMLNode ----------- //

 

 XMLNode::XMLNode( XMLDocument* doc ) :

@@ -314,12 +328,12 @@
 }

 

 

-XMLElement* XMLNode::FirstChildElement( const char* value )

+const XMLElement* XMLNode::FirstChildElement( const char* value ) const

 {

 	for( XMLNode* node=firstChild; node; node=node->next ) {

 		XMLElement* element = node->ToElement();

 		if ( element ) {

-			if ( !value || XMLBase::StringEqual( element->Name(), value ) ) {

+			if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {

 				return element;

 			}

 		}

@@ -328,6 +342,27 @@
 }

 

 

+const XMLElement* XMLNode::LastChildElement( const char* value ) const

+{

+	for( XMLNode* node=lastChild; node; node=node->prev ) {

+		XMLElement* element = node->ToElement();

+		if ( element ) {

+			if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {

+				return element;

+			}

+		}

+	}

+	return 0;

+}

+

+

+void XMLNode::DeleteChild( XMLNode* node )

+{

+	TIXMLASSERT( node->parent == this );

+	TIXMLASSERT( 0 );

+}

+

+

 void XMLNode::Print( XMLStreamer* streamer )

 {

 	for( XMLNode* node = firstChild; node; node=node->next ) {

@@ -357,7 +392,7 @@
 // --------- XMLText ---------- //

 char* XMLText::ParseDeep( char* p )

 {

-	p = XMLBase::ParseText( p, &value, "<", StrPair::TEXT_ELEMENT );

+	p = value.ParseText( p, "<", StrPair::TEXT_ELEMENT );

 	// consumes the end tag.

 	if ( p && *p ) {

 		return p-1;

@@ -373,6 +408,12 @@
 }

 

 

+bool XMLText::Accept( XMLVisitor* visitor ) const

+{

+	return visitor->Visit( *this );

+}

+

+

 // --------- XMLComment ---------- //

 

 XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )

@@ -397,19 +438,25 @@
 char* XMLComment::ParseDeep( char* p )

 {

 	// Comment parses as text.

-	return XMLBase::ParseText( p, &value, "-->", StrPair::COMMENT );

+	return value.ParseText( p, "-->", StrPair::COMMENT );

 }

 

 

+bool XMLComment::Accept( XMLVisitor* visitor ) const
+{
+	return visitor->Visit( *this );
+}
+

+

 // --------- XMLAttribute ---------- //

 char* XMLAttribute::ParseDeep( char* p )

 {

-	p = XMLBase::ParseText( p, &name, "=", StrPair::ATTRIBUTE_NAME );

+	p = name.ParseText( p, "=", StrPair::ATTRIBUTE_NAME );

 	if ( !p || !*p ) return 0;

 

 	char endTag[2] = { *p, 0 };

 	++p;

-	p = XMLBase::ParseText( p, &value, endTag, StrPair::ATTRIBUTE_VALUE );

+	p = value.ParseText( p, endTag, StrPair::ATTRIBUTE_VALUE );

 	if ( value.Empty() ) return 0;

 	return p;

 }

@@ -452,14 +499,14 @@
 

 	// Read the attributes.

 	while( p ) {

-		p = XMLBase::SkipWhiteSpace( p );

+		p = XMLUtil::SkipWhiteSpace( p );

 		if ( !p || !(*p) ) {

 			document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, Name() );

 			return 0;

 		}

 

 		// attribute.

-		if ( XMLBase::IsAlpha( *p ) ) {

+		if ( XMLUtil::IsAlpha( *p ) ) {

 			XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute( this );

 			attrib->memPool = &document->attributePool;

 

@@ -508,7 +555,7 @@
 char* XMLElement::ParseDeep( char* p )

 {

 	// Read the element name.

-	p = XMLBase::SkipWhiteSpace( p );

+	p = XMLUtil::SkipWhiteSpace( p );

 	if ( !p ) return 0;

 	const char* start = p;

 

@@ -520,7 +567,7 @@
 		++p;

 	}

 

-	p = XMLBase::ParseName( p, &value );

+	p = value.ParseName( p );

 	if ( value.Empty() ) return 0;

 

 	bool elementClosed=false;

@@ -539,7 +586,7 @@
 	//	PrintSpace( cfile, depth );

 	//}

 	//fprintf( cfile, "<%s", Name() );

-	streamer->OpenElement( Name(), IsTextParent() );

+	streamer->OpenElement( Name() );

 

 	for( XMLAttribute* attrib=rootAttribute; attrib; attrib=attrib->next ) {

 		//fprintf( cfile, " " );

@@ -554,6 +601,21 @@
 }

 

 

+bool XMLElement::Accept( XMLVisitor* visitor ) const
+{
+	if ( visitor->VisitEnter( *this, rootAttribute ) ) 
+	{
+		for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
+		{
+			if ( !node->Accept( visitor ) )
+				break;
+		}
+	}
+	return visitor->VisitExit( *this );
+
+}
+

+

 // --------- XMLDocument ----------- //

 XMLDocument::XMLDocument() :

 	XMLNode( 0 ),

@@ -678,7 +740,7 @@
 */

 

 

-XMLStreamer::XMLStreamer( FILE* file ) : fp( file ), depth( 0 ), elementJustOpened( false )

+XMLStreamer::XMLStreamer( FILE* file ) : fp( file ), depth( 0 ), elementJustOpened( false ), textDepth( -1 )

 {

 	for( int i=0; i<ENTITY_RANGE; ++i ) {

 		entityFlag[i] = false;

@@ -733,18 +795,18 @@
 	}

 }

 

-void XMLStreamer::OpenElement( const char* name, bool textParent )

+void XMLStreamer::OpenElement( const char* name )

 {

 	if ( elementJustOpened ) {

 		SealElement();

 	}

-	if ( !TextOnStack() ) {

+	stack.Push( name );

+

+	if ( textDepth < 0 && depth > 0) {

+		fprintf( fp, "\n" );

 		PrintSpace( depth );

 	}

-	stack.Push( name );

-	text.Push( textParent ? 'T' : 'e' );

 

-	// fixme: can names have entities?

 	fprintf( fp, "<%s", name );

 	elementJustOpened = true;

 	++depth;

@@ -764,25 +826,22 @@
 {

 	--depth;

 	const char* name = stack.Pop();

-	bool wasText = TextOnStack();

-	text.Pop();

 

 	if ( elementJustOpened ) {

 		fprintf( fp, "/>" );

-		if ( !wasText ) {

-			fprintf( fp, "\n" );

-		}

 	}

 	else {

-		if ( !wasText ) {

+		if ( textDepth < 0 ) {

+			fprintf( fp, "\n" );

 			PrintSpace( depth );

 		}

-		// fixme can names have entities?

 		fprintf( fp, "</%s>", name );

-		if ( !TextOnStack() ) {

-			fprintf( fp, "\n" );

-		}

 	}

+

+	if ( textDepth == depth )

+		textDepth = -1;

+	if ( depth == 0 )

+		fprintf( fp, "\n" );

 	elementJustOpened = false;

 }

 

@@ -791,14 +850,13 @@
 {

 	elementJustOpened = false;

 	fprintf( fp, ">" );

-	if ( !TextOnStack() ) {

-		fprintf( fp, "\n" );

-	}

 }

 

 

 void XMLStreamer::PushText( const char* text )

 {

+	textDepth = depth-1;

+

 	if ( elementJustOpened ) {

 		SealElement();

 	}

diff --git a/tinyxml2.h b/tinyxml2.h
index 2a6e344..cfe297f 100644
--- a/tinyxml2.h
+++ b/tinyxml2.h
@@ -12,7 +12,7 @@
 	- make constructors protected

 	- hide copy constructor

 	- hide = operator

-	- UTF8 support: isAlpha, etc.

+	X UTF8 support: isAlpha, etc.

 */

 

 #include <limits.h>

@@ -74,6 +74,9 @@
 	bool Empty() const { return start == end; }

 

 	void SetInternedStr( const char* str ) { this->start = (char*) str; this->end = 0; this->flags = 0; }

+	char* ParseText( char* in, const char* endTag, int strFlags );

+	char* ParseName( char* in );

+

 

 private:

 	enum {

@@ -278,16 +281,59 @@
 };

 */

 

-class XMLBase

+

+/**

+	Implements the interface to the "Visitor pattern" (see the Accept() method.)

+	If you call the Accept() method, it requires being passed a XMLVisitor

+	class to handle callbacks. For nodes that contain other nodes (Document, Element)

+	you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves

+	are simply called with Visit().

+

+	If you return 'true' from a Visit method, recursive parsing will continue. If you return

+	false, <b>no children of this node or its sibilings</b> will be Visited.

+

+	All flavors of Visit methods have a default implementation that returns 'true' (continue 

+	visiting). You need to only override methods that are interesting to you.

+

+	Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.

+

+	You should never change the document from a callback.

+

+	@sa XMLNode::Accept()

+*/

+class XMLVisitor

 {

 public:

+	virtual ~XMLVisitor() {}

 

+	/// Visit a document.

+	virtual bool VisitEnter( const XMLDocument& /*doc*/ )			{ return true; }

+	/// Visit a document.

+	virtual bool VisitExit( const XMLDocument& /*doc*/ )			{ return true; }

+

+	/// Visit an element.

+	virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ )	{ return true; }

+	/// Visit an element.

+	virtual bool VisitExit( const XMLElement& /*element*/ )			{ return true; }

+

+	/// Visit a declaration

+	//virtual bool Visit( const TiXmlDeclaration& /*declaration*/ )	{ return true; }

+	/// Visit a text node

+	virtual bool Visit( const XMLText& /*text*/ )					{ return true; }

+	/// Visit a comment node

+	virtual bool Visit( const XMLComment& /*comment*/ )				{ return true; }

+	/// Visit an unknown node

+	//virtual bool Visit( const TiXmlUnknown& /*unknown*/ )			{ return true; }

+};

+

+

+class XMLUtil

+{

 public:

-	XMLBase() {}

-	virtual ~XMLBase() {}

-

-	static const char* SkipWhiteSpace( const char* p )	{ while( isspace( *p ) ) { ++p; } return p; }

-	static char* SkipWhiteSpace( char* p )				{ while( isspace( *p ) ) { ++p; } return p; }

+	// Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't 

+	// correct, but simple, and usually works.

+	static const char* SkipWhiteSpace( const char* p )	{ while( IsUTF8Continuation(*p) || isspace( *p ) ) { ++p; } return p; }

+	static char* SkipWhiteSpace( char* p )				{ while( IsUTF8Continuation(*p) || isspace( *p ) ) { ++p; } return p; }

 

 	inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX )  {

 		int n = 0;

@@ -303,13 +349,8 @@
 		return false;

 	}

 	inline static int IsUTF8Continuation( unsigned char p ) { return p & 0x80; }

-	inline static int IsAlphaNum( unsigned char anyByte )	{ return ( anyByte <= 127 ) ? isalnum( anyByte ) : 1; }

-	inline static int IsAlpha( unsigned char anyByte )		{ return ( anyByte <= 127 ) ? isalpha( anyByte ) : 1; }

-

-	static char* ParseText( char* in, StrPair* pair, const char* endTag, int strFlags );

-	static char* ParseName( char* in, StrPair* pair );

-

-private:

+	inline static int IsAlphaNum( unsigned char anyByte )	{ return ( anyByte < 128 ) ? isalnum( anyByte ) : 1; }

+	inline static int IsAlpha( unsigned char anyByte )		{ return ( anyByte < 128 ) ? isalpha( anyByte ) : 1; }

 };

 

 

@@ -318,25 +359,50 @@
 	friend class XMLDocument;

 	friend class XMLElement;

 public:

-	//void* operator new( size_t size, MemPool* pool );

-	//void operator delete( void* mem, MemPool* pool );

+	XMLDocument* GetDocument()				{ return document; }

 

-	XMLNode* InsertEndChild( XMLNode* addThis );

-	virtual void Print( XMLStreamer* streamer );

+	virtual XMLElement*		ToElement()		{ return 0; }

+	virtual XMLText*		ToText()		{ return 0; }

+	virtual XMLComment*		ToComment()		{ return 0; }

+	virtual XMLDocument*	ToDocument()	{ return 0; }

 

 	const char* Value() const			{ return value.GetStr(); }

 	void SetValue( const char* val )	{ value.SetInternedStr( val ); }

 

-	virtual XMLElement* ToElement()		{ return 0; }

-	virtual XMLText*	ToText()		{ return 0; }

-	virtual XMLComment* ToComment()		{ return 0; }

+	const XMLNode*  FirstChild() const		{ return firstChild; }

+	XMLNode*		FirstChild()			{ return firstChild; }

+	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 )); }

 

-	XMLNode* FirstChild()	{ return firstChild; }

-	XMLElement* FirstChildElement( const char* value=0 );

+	const XMLNode*	LastChild() const						{ return lastChild; }

+	XMLNode*		LastChild()								{ return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); }

 

-	// fixme: guarentee null terminator to avoid internal checks

+	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) ); }

+	

+	const XMLNode*	PreviousSibling() const					{ return prev; }

+	XMLNode*	PreviousSibling()							{ return prev; }

+

+	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 ) ); }

+	

+	const XMLNode*	NextSibling() const						{ return next; }

+	XMLNode*	NextSibling()								{ return next; }

+		

+	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* InsertEndChild( XMLNode* addThis );

+	XMLNode* InsertFirstChild( XMLNode* addThis );

+	XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );

+	

+	void ClearChildren();

+	void DeleteChild( XMLNode* node );

+

+	virtual bool Accept( XMLVisitor* visitor ) const = 0;

+	virtual void Print( XMLStreamer* streamer );

+

 	virtual char* ParseDeep( char* );

-

 	void SetTextParent()		{ isTextParent = true; } 

 	bool IsTextParent() const	{ return isTextParent; }

 	virtual bool IsClosingElement() const { return false; }

@@ -345,8 +411,6 @@
 	XMLNode( XMLDocument* );

 	virtual ~XMLNode();

 	

-	void ClearChildren();

-

 	XMLDocument*	document;

 	XMLNode*		parent;

 	bool			isTextParent;

@@ -373,6 +437,7 @@
 	const char* Value() { return value.GetStr(); }

 	void SetValue( const char* );

 

+	virtual bool Accept( XMLVisitor* visitor ) const;

 	virtual XMLText*	ToText()		{ return this; }

 

 	char* ParseDeep( char* );

@@ -394,6 +459,7 @@
 	virtual XMLComment*	ToComment()		{ return this; }

 

 	const char* Value() { return value.GetStr(); }

+	virtual bool Accept( XMLVisitor* visitor ) const;

 

 	char* ParseDeep( char* );

 

@@ -405,7 +471,7 @@
 };

 

 

-class XMLAttribute : public XMLBase

+class XMLAttribute

 {

 	friend class XMLElement;

 public:

@@ -434,6 +500,7 @@
 	virtual void Print( XMLStreamer* );

 

 	virtual XMLElement* ToElement() { return this; }

+	virtual bool Accept( XMLVisitor* visitor ) const;

 

 	// internal:

 	virtual bool IsClosingElement() const { return closing; }

@@ -459,11 +526,14 @@
 	XMLDocument(); 

 	~XMLDocument();

 

+	virtual XMLDocument*	ToDocument()	{ return this; }

+

 	int Parse( const char* );

 	int Load( const char* );

 	int Load( FILE* );

 

 	void Print( XMLStreamer* streamer=0 );

+	virtual bool Accept( XMLVisitor* visitor ) const;

 

 	XMLElement* NewElement( const char* name );

 

@@ -500,13 +570,13 @@
 };

 

 

-class XMLStreamer

+class XMLStreamer 

 {

 public:

 	XMLStreamer( FILE* file );

 	~XMLStreamer()	{}

 

-	void OpenElement( const char* name, bool textParent );

+	void OpenElement( const char* name );

 	void PushAttribute( const char* name, const char* value );

 	void CloseElement();

 

@@ -517,24 +587,26 @@
 	void SealElement();

 	void PrintSpace( int depth );

 	void PrintString( const char* );	// prints out, after detecting entities.

-	bool TextOnStack() const { 

+/*	bool TextOnStack() const { 

 		for( int i=0; i<text.Size(); ++i ) { 

 			if ( text[i] == 'T' ) 

 				return true; 

 		} 

 		return false; 

-	}

+	}*/

 

 	FILE* fp;

 	int depth;

 	bool elementJustOpened;

+	int textDepth;

+

 	enum {

 		ENTITY_RANGE = 64

 	};

 	bool entityFlag[ENTITY_RANGE];

 

 	DynArray< const char*, 10 > stack;

-	DynArray< char, 10 > text;

+	//DynArray< char, 10 > text;

 };

 

 

diff --git a/xmltest.cpp b/xmltest.cpp
index 243f0fa..7be7c2e 100644
--- a/xmltest.cpp
+++ b/xmltest.cpp
@@ -52,6 +52,7 @@
 			printf( "----------------------------------------------\n" );

 		}

 	}

+#if 0

 	{

 		static const char* test = "<element>Text before.</element>";

 		XMLDocument doc;

@@ -67,5 +68,6 @@
 		doc->Parse( test );

 		delete doc;

 	}

+#endif

 	return 0;

 }
\ No newline at end of file