Moving string in/out into XMLUtil. Using that across the API. Supporting text queries of primitive types.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 53f09c2..4b60d7c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,7 +10,7 @@
 ################################
 # set lib version here
 
-set(GENERIC_LIB_VERSION "1.0.5")
+set(GENERIC_LIB_VERSION "1.0.6")
 set(GENERIC_LIB_SOVERSION "1")
 
 
diff --git a/dox b/dox
index 5a9e9d3..c435bbf 100755
--- a/dox
+++ b/dox
@@ -32,7 +32,7 @@
 # This could be handy for archiving the generated documentation or

 # if some version control system is used.

 

-PROJECT_NUMBER = 1.0.5
+PROJECT_NUMBER = 1.0.6
 

 # Using the PROJECT_BRIEF tag one can provide an optional one line description

 # for a project that appears at the top of each page and should give viewer

diff --git a/tinyxml2.cpp b/tinyxml2.cpp
index 08917e1..b7dd909 100644
--- a/tinyxml2.cpp
+++ b/tinyxml2.cpp
@@ -369,6 +369,86 @@
 }

 

 

+void XMLUtil::ToStr( int v, char* buffer, int bufferSize ) 

+{

+	TIXML_SNPRINTF( buffer, bufferSize, "%d", v );	

+}

+

+

+void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )

+{

+	TIXML_SNPRINTF( buffer, bufferSize, "%u", v );	

+}

+

+

+void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )

+{

+	TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );	

+}

+

+

+void XMLUtil::ToStr( float v, char* buffer, int bufferSize )

+{

+	TIXML_SNPRINTF( buffer, bufferSize, "%f", v );	

+}

+

+

+void XMLUtil::ToStr( double v, char* buffer, int bufferSize )

+{

+	TIXML_SNPRINTF( buffer, bufferSize, "%f", v );	

+}

+

+

+bool XMLUtil::ToInt( const char* str, int* value )

+{

+	if ( TIXML_SSCANF( str, "%d", value ) == 1 )

+		return true;

+	return false;

+}

+

+bool XMLUtil::ToUnsigned( const char* str, unsigned *value )

+{

+	if ( TIXML_SSCANF( str, "%u", value ) == 1 )

+		return true;

+	return false;

+}

+

+bool XMLUtil::ToBool( const char* str, bool* value )

+{

+	int ival = 0;

+	if ( ToInt( str, &ival )) {

+		*value = (ival==0) ? false : true;

+		return true;

+	}

+	if ( StringEqual( str, "true" ) ) {

+		*value = true;

+		return true;

+	}

+	else if ( StringEqual( str, "false" ) ) {

+		*value = false;

+		return true;

+	}

+	return false;

+}

+

+

+bool XMLUtil::ToFloat( const char* str, float* value )

+{

+	if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {

+		return true;

+	}

+	return false;

+}

+

+bool XMLUtil::ToDouble( const char* str, double* value )

+{

+	if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {

+		return true;

+	}

+	return false;

+}

+

+

 char* XMLDocument::Identify( char* p, XMLNode** node ) 

 {

 	XMLNode* returnNode = 0;

@@ -942,7 +1022,7 @@
 

 int XMLAttribute::QueryIntValue( int* value ) const

 {

-	if ( TIXML_SSCANF( Value(), "%d", value ) == 1 )

+	if ( XMLUtil::ToInt( Value(), value ))

 		return XML_NO_ERROR;

 	return XML_WRONG_ATTRIBUTE_TYPE;

 }

@@ -950,7 +1030,7 @@
 

 int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const

 {

-	if ( TIXML_SSCANF( Value(), "%u", value ) == 1 )

+	if ( XMLUtil::ToUnsigned( Value(), value ))

 		return XML_NO_ERROR;

 	return XML_WRONG_ATTRIBUTE_TYPE;

 }

@@ -958,32 +1038,24 @@
 

 int XMLAttribute::QueryBoolValue( bool* value ) const

 {

-	int ival = -1;

-	QueryIntValue( &ival );

-

-	if ( ival > 0 || XMLUtil::StringEqual( Value(), "true" ) ) {

-		*value = true;

+	if ( XMLUtil::ToBool( Value(), value )) {

 		return XML_NO_ERROR;

 	}

-	else if ( ival == 0 || XMLUtil::StringEqual( Value(), "false" ) ) {

-		*value = false;

-		return XML_NO_ERROR;

-	}

-	return XML_WRONG_ATTRIBUTE_TYPE;

-}

-

-

-int XMLAttribute::QueryDoubleValue( double* value ) const

-{

-	if ( TIXML_SSCANF( Value(), "%lf", value ) == 1 )

-		return XML_NO_ERROR;

 	return XML_WRONG_ATTRIBUTE_TYPE;

 }

 

 

 int XMLAttribute::QueryFloatValue( float* value ) const

 {

-	if ( TIXML_SSCANF( Value(), "%f", value ) == 1 )

+	if ( XMLUtil::ToFloat( Value(), value ))

+		return XML_NO_ERROR;

+	return XML_WRONG_ATTRIBUTE_TYPE;

+}

+

+

+int XMLAttribute::QueryDoubleValue( double* value ) const

+{

+	if ( XMLUtil::ToDouble( Value(), value ))

 		return XML_NO_ERROR;

 	return XML_WRONG_ATTRIBUTE_TYPE;

 }

@@ -998,7 +1070,7 @@
 void XMLAttribute::SetAttribute( int v )

 {

 	char buf[BUF_SIZE];

-	TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v );	

+	XMLUtil::ToStr( v, buf, BUF_SIZE );

 	value.SetStr( buf );

 }

 

@@ -1006,7 +1078,7 @@
 void XMLAttribute::SetAttribute( unsigned v )

 {

 	char buf[BUF_SIZE];

-	TIXML_SNPRINTF( buf, BUF_SIZE, "%u", v );	

+	XMLUtil::ToStr( v, buf, BUF_SIZE );

 	value.SetStr( buf );

 }

 

@@ -1014,21 +1086,21 @@
 void XMLAttribute::SetAttribute( bool v )

 {

 	char buf[BUF_SIZE];

-	TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v ? 1 : 0 );	

+	XMLUtil::ToStr( v, buf, BUF_SIZE );

 	value.SetStr( buf );

 }

 

 void XMLAttribute::SetAttribute( double v )

 {

 	char buf[BUF_SIZE];

-	TIXML_SNPRINTF( buf, BUF_SIZE, "%f", v );	

+	XMLUtil::ToStr( v, buf, BUF_SIZE );

 	value.SetStr( buf );

 }

 

 void XMLAttribute::SetAttribute( float v )

 {

 	char buf[BUF_SIZE];

-	TIXML_SNPRINTF( buf, BUF_SIZE, "%f", v );	

+	XMLUtil::ToStr( v, buf, BUF_SIZE );

 	value.SetStr( buf );

 }

 

@@ -1093,6 +1165,72 @@
 }

 

 

+int XMLElement::QueryIntText( int* _value ) const

+{

+	if ( FirstChild() && FirstChild()->ToText() ) {

+		const char* t = FirstChild()->ToText()->Value();

+		if ( XMLUtil::ToInt( t, _value ) ) {

+			return XML_SUCCESS;

+		}

+		return XML_CAN_NOT_CONVERT_TEXT;

+	}

+	return XML_NO_TEXT_NODE;

+}

+

+

+int XMLElement::QueryUnsignedText( unsigned* _value ) const

+{

+	if ( FirstChild() && FirstChild()->ToText() ) {

+		const char* t = FirstChild()->ToText()->Value();

+		if ( XMLUtil::ToUnsigned( t, _value ) ) {

+			return XML_SUCCESS;

+		}

+		return XML_CAN_NOT_CONVERT_TEXT;

+	}

+	return XML_NO_TEXT_NODE;

+}

+

+

+int XMLElement::QueryBoolText( bool* _value ) const

+{

+	if ( FirstChild() && FirstChild()->ToText() ) {

+		const char* t = FirstChild()->ToText()->Value();

+		if ( XMLUtil::ToBool( t, _value ) ) {

+			return XML_SUCCESS;

+		}

+		return XML_CAN_NOT_CONVERT_TEXT;

+	}

+	return XML_NO_TEXT_NODE;

+}

+

+

+int XMLElement::QueryDoubleText( double* _value ) const

+{

+	if ( FirstChild() && FirstChild()->ToText() ) {

+		const char* t = FirstChild()->ToText()->Value();

+		if ( XMLUtil::ToDouble( t, _value ) ) {

+			return XML_SUCCESS;

+		}

+		return XML_CAN_NOT_CONVERT_TEXT;

+	}

+	return XML_NO_TEXT_NODE;

+}

+

+

+int XMLElement::QueryFloatText( float* _value ) const

+{

+	if ( FirstChild() && FirstChild()->ToText() ) {

+		const char* t = FirstChild()->ToText()->Value();

+		if ( XMLUtil::ToFloat( t, _value ) ) {

+			return XML_SUCCESS;

+		}

+		return XML_CAN_NOT_CONVERT_TEXT;

+	}

+	return XML_NO_TEXT_NODE;

+}

+

+

+

 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )

 {

 	XMLAttribute* last = 0;

@@ -1668,7 +1806,7 @@
 void XMLPrinter::PushAttribute( const char* name, int v )

 {

 	char buf[BUF_SIZE];

-	TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v );	

+	XMLUtil::ToStr( v, buf, BUF_SIZE );

 	PushAttribute( name, buf );

 }

 

@@ -1676,7 +1814,7 @@
 void XMLPrinter::PushAttribute( const char* name, unsigned v )

 {

 	char buf[BUF_SIZE];

-	TIXML_SNPRINTF( buf, BUF_SIZE, "%u", v );	

+	XMLUtil::ToStr( v, buf, BUF_SIZE );

 	PushAttribute( name, buf );

 }

 

@@ -1684,7 +1822,7 @@
 void XMLPrinter::PushAttribute( const char* name, bool v )

 {

 	char buf[BUF_SIZE];

-	TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v ? 1 : 0 );	

+	XMLUtil::ToStr( v, buf, BUF_SIZE );

 	PushAttribute( name, buf );

 }

 

@@ -1692,7 +1830,7 @@
 void XMLPrinter::PushAttribute( const char* name, double v )

 {

 	char buf[BUF_SIZE];

-	TIXML_SNPRINTF( buf, BUF_SIZE, "%f", v );	

+	XMLUtil::ToStr( v, buf, BUF_SIZE );

 	PushAttribute( name, buf );

 }

 

@@ -1745,6 +1883,45 @@
 	}

 }

 

+void XMLPrinter::PushText( int value ) 

+{

+	char buf[BUF_SIZE];

+	XMLUtil::ToStr( value, buf, BUF_SIZE );

+	PushText( buf, false );

+}

+

+

+void XMLPrinter::PushText( unsigned value ) 

+{

+	char buf[BUF_SIZE];

+	XMLUtil::ToStr( value, buf, BUF_SIZE );

+	PushText( buf, false );

+}

+

+

+void XMLPrinter::PushText( bool value ) 

+{

+	char buf[BUF_SIZE];

+	XMLUtil::ToStr( value, buf, BUF_SIZE );

+	PushText( buf, false );

+}

+

+

+void XMLPrinter::PushText( float value ) 

+{

+	char buf[BUF_SIZE];

+	XMLUtil::ToStr( value, buf, BUF_SIZE );

+	PushText( buf, false );

+}

+

+

+void XMLPrinter::PushText( double value ) 

+{

+	char buf[BUF_SIZE];

+	XMLUtil::ToStr( value, buf, BUF_SIZE );

+	PushText( buf, false );

+}

+

 

 void XMLPrinter::PushComment( const char* comment )

 {

diff --git a/tinyxml2.h b/tinyxml2.h
index a47cc62..13629f4 100644
--- a/tinyxml2.h
+++ b/tinyxml2.h
@@ -85,7 +85,7 @@
 

 static const int TIXML2_MAJOR_VERSION = 1;

 static const int TIXML2_MINOR_VERSION = 0;

-static const int TIXML2_PATCH_VERSION = 5;

+static const int TIXML2_PATCH_VERSION = 6;

 

 namespace tinyxml2

 {

@@ -388,6 +388,20 @@
 	// the UTF-8 value of the entity will be placed in value, and length filled in.

 	static const char* GetCharacterRef( const char* p, char* value, int* length );

 	static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );

+

+	// converts primitive types to strings

+	static void ToStr( int v, char* buffer, int bufferSize );

+	static void ToStr( unsigned v, char* buffer, int bufferSize );

+	static void ToStr( bool v, char* buffer, int bufferSize );

+	static void ToStr( float v, char* buffer, int bufferSize );

+	static void ToStr( double v, char* buffer, int bufferSize );

+

+	// converts strings to primitive types

+	static bool	ToInt( const char* str, int* value );

+	static bool ToUnsigned( const char* str, unsigned* value );

+	static bool	ToBool( const char* str, bool* value );

+	static bool	ToFloat( const char* str, float* value );

+	static bool ToDouble( const char* str, double* value );

 };

 

 

@@ -739,7 +753,10 @@
 	XML_ERROR_PARSING_UNKNOWN,

 	XML_ERROR_EMPTY_DOCUMENT,

 	XML_ERROR_MISMATCHED_ELEMENT,

-	XML_ERROR_PARSING

+	XML_ERROR_PARSING,

+

+	XML_CAN_NOT_CONVERT_TEXT,

+	XML_NO_TEXT_NODE

 };

 

 

@@ -928,7 +945,7 @@
 		This is a convenient method for getting the text of simple contained text:

 		@verbatim

 		<foo>This is text</foo>

-		const char* str = fooElement->GetText();

+			const char* str = fooElement->GetText();

 		@endverbatim

 

 		'str' will be a pointer to "This is text". 

@@ -936,18 +953,54 @@
 		Note that this function can be misleading. If the element foo was created from

 		this XML:

 		@verbatim

-		<foo><b>This is text</b></foo> 

+			<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> 

+			<foo>This is <b>text</b></foo> 

 		@endverbatim

 		GetText() will return "This is ".

 	*/

 	const char* GetText() const;

 

+	/** 

+		Convenience method to query the value of a child text node. This is probably best

+		shown by example. Given you have a document is this form:

+		@verbatim

+			<point>

+				<x>1</x>

+				<y>1.4</y>

+			</point>

+		@endverbatim

+

+		The QueryIntText() and similar functions provide a safe and easier way to get to the

+		"value" of x and y.

+

+		@verbatim

+			int x = 0;

+			float y = 0;	// types of x and y are contrived for example

+			const XMLElement* xElement = pointElement->FirstChildElement( "x" );

+			const XMLElement* yElement = pointElement->FirstChildElement( "y" );

+			xElement->QueryIntText( &x );

+			yElement->QueryFloatText( &y );

+		@endverbatim

+

+		@returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted

+				 to the requested type, and XML_NO_TEXT_NODE if there is no child text to query.

+			

+	*/

+	int QueryIntText( int* _value ) const;

+	/// See QueryIntText()

+	int QueryUnsignedText( unsigned* _value ) const;

+	/// See QueryIntText()

+	int QueryBoolText( bool* _value ) const;

+	/// See QueryIntText()

+	int QueryDoubleText( double* _value ) const;

+	/// See QueryIntText()

+	int QueryFloatText( float* _value ) const;

+

 	// internal:

 	enum {

 		OPEN,		// <foo>

@@ -1352,7 +1405,18 @@
 

 	/// Add a text node.

 	void PushText( const char* text, bool cdata=false );

-	/// Add a comment.

+	/// Add a text node from an integer.

+	void PushText( int value );

+	/// Add a text node from an unsigned.

+	void PushText( unsigned value );

+	/// Add a text node from a bool.

+	void PushText( bool value );

+	/// Add a text node from a float.

+	void PushText( float value );

+	/// Add a text node from a double.

+	void PushText( double value );

+

+	/// Add a comment

 	void PushComment( const char* comment );

 

 	void PushDeclaration( const char* value );

diff --git a/xmltest.cpp b/xmltest.cpp
index 760d0e2..7916a05 100644
--- a/xmltest.cpp
+++ b/xmltest.cpp
@@ -38,7 +38,7 @@
 }

 

 

-bool XMLTest( const char* testString, int expected, int found, bool echo=true )

+template< class T > bool XMLTest( const char* testString, T expected, T found, bool echo=true )

 {

 	bool pass = ( expected == found );

 	if ( pass )

@@ -116,6 +116,34 @@
 }

 

 

+bool example_4()

+{

+	static const char* xml =

+		"<information>"

+		"	<attributeApproach v='2' />"

+		"	<textApproach>"

+		"		<v>2</v>"

+		"	</textApproach>"

+		"</information>";

+	

+	XMLDocument doc;

+	doc.Parse( xml );

+

+	int v0 = 0;

+	int v1 = 0;

+

+	XMLElement* attributeApproachElement = doc.FirstChildElement()->FirstChildElement( "attributeApproach" );

+	attributeApproachElement->QueryIntAttribute( "v", &v0 );

+

+	XMLElement* textApproachElement = doc.FirstChildElement()->FirstChildElement( "textApproach" );

+	textApproachElement->FirstChildElement( "v" )->QueryIntText( &v1 );

+

+	printf( "Both values are the same: %d and %d\n", v0, v1 );

+

+	return !doc.Error() && ( v0 == v1 );

+}

+

+

 int main( int /*argc*/, const char ** /*argv*/ )

 {

 	#if defined( _MSC_VER ) && defined( DEBUG )

@@ -148,6 +176,7 @@
 	XMLTest( "Example-1", 0, example_1() );

 	XMLTest( "Example-2", 0, example_2() );

 	XMLTest( "Example-3", 0, example_3() );

+	XMLTest( "Example-4", true, example_4() );

 

 	/* ------ Example 2: Lookup information. ---- */	

 

@@ -243,7 +272,7 @@
 		XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );

 		int value = 10;

 		int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value );

-		XMLTest( "Programmatic DOM", result, XML_NO_ATTRIBUTE );

+		XMLTest( "Programmatic DOM", result, (int)XML_NO_ATTRIBUTE );

 		XMLTest( "Programmatic DOM", value, 10 );

 

 		doc->Print();

@@ -303,7 +332,7 @@
 

 		XMLDocument doc;

 		doc.Parse( error );

-		XMLTest( "Bad XML", doc.ErrorID(), XML_ERROR_PARSING_ATTRIBUTE );

+		XMLTest( "Bad XML", doc.ErrorID(), (int)XML_ERROR_PARSING_ATTRIBUTE );

 	}

 

 	{

@@ -318,17 +347,17 @@
 		double dVal;

 

 		result = ele->QueryDoubleAttribute( "attr0", &dVal );

-		XMLTest( "Query attribute: int as double", result, XML_NO_ERROR );

+		XMLTest( "Query attribute: int as double", result, (int)XML_NO_ERROR );

 		XMLTest( "Query attribute: int as double", (int)dVal, 1 );

 		result = ele->QueryDoubleAttribute( "attr1", &dVal );

 		XMLTest( "Query attribute: double as double", (int)dVal, 2 );

 		result = ele->QueryIntAttribute( "attr1", &iVal );

-		XMLTest( "Query attribute: double as int", result, XML_NO_ERROR );

+		XMLTest( "Query attribute: double as int", result, (int)XML_NO_ERROR );

 		XMLTest( "Query attribute: double as int", iVal, 2 );

 		result = ele->QueryIntAttribute( "attr2", &iVal );

-		XMLTest( "Query attribute: not a number", result, XML_WRONG_ATTRIBUTE_TYPE );

+		XMLTest( "Query attribute: not a number", result, (int)XML_WRONG_ATTRIBUTE_TYPE );

 		result = ele->QueryIntAttribute( "bar", &iVal );

-		XMLTest( "Query attribute: does not exist", result, XML_NO_ATTRIBUTE );

+		XMLTest( "Query attribute: does not exist", result, (int)XML_NO_ATTRIBUTE );

 	}

 

 	{

@@ -566,7 +595,7 @@
 

 		XMLDocument doc;

         doc.Parse( test );

-        XMLTest( "dot in names", doc.Error(), 0);

+        XMLTest( "dot in names", doc.Error(), false );

         XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" );

         XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" );

 	}

@@ -623,7 +652,7 @@
 		XMLDocument doc;

 		doc.Parse( doctype );

 		

-		XMLTest( "Parsing repeated attributes.", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );	// is an  error to tinyxml (didn't use to be, but caused issues)

+		XMLTest( "Parsing repeated attributes.", (int)XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );	// is an  error to tinyxml (didn't use to be, but caused issues)

 		doc.PrintError();

 	}

 

@@ -641,7 +670,7 @@
 		const char* str = "    ";

 		XMLDocument doc;

 		doc.Parse( str );

-		XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );

+		XMLTest( "Empty document error", (int)XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );

 	}

 

 	{

@@ -668,7 +697,7 @@
 		xml.Parse("<x> ");

 		XMLTest("Missing end tag with trailing whitespace", xml.Error(), true);

 		xml.Parse("<x></y>");

-		XMLTest("Mismatched tags", xml.ErrorID(), XML_ERROR_MISMATCHED_ELEMENT);

+		XMLTest("Mismatched tags", xml.ErrorID(), (int)XML_ERROR_MISMATCHED_ELEMENT);

 	} 

 

 

@@ -865,6 +894,40 @@
 		XMLTest( "BOM and default declaration", printer.CStr(), result, false );

 		XMLTest( "CStrSize", printer.CStrSize(), 42, false );

 	}

+	{

+		const char* xml = "<ipxml ws='1'><info bla=' /></ipxml>";

+		XMLDocument doc;

+		doc.Parse( xml );

+		XMLTest( "Ill formed XML", true, doc.Error() );

+	}

+

+	// QueryXYZText

+	{

+		const char* xml = "<point> <x>1.2</x> <y>1</y> <z>38</z> <valid>true</valid> </point>";

+		XMLDocument doc;

+		doc.Parse( xml );

+

+		const XMLElement* pointElement = doc.RootElement();

+

+		int intValue = 0;

+		unsigned unsignedValue = 0;

+		float floatValue = 0;

+		double doubleValue = 0;

+		bool boolValue = false;

+

+		pointElement->FirstChildElement( "y" )->QueryIntText( &intValue );

+		pointElement->FirstChildElement( "y" )->QueryUnsignedText( &unsignedValue );

+		pointElement->FirstChildElement( "x" )->QueryFloatText( &floatValue );

+		pointElement->FirstChildElement( "x" )->QueryDoubleText( &doubleValue );

+		pointElement->FirstChildElement( "valid" )->QueryBoolText( &boolValue );

+

+

+		XMLTest( "QueryIntText", intValue, 1,						false );

+		XMLTest( "QueryUnsignedText", unsignedValue, (unsigned)1,	false );

+		XMLTest( "QueryFloatText", floatValue, 1.2f,				false );

+		XMLTest( "QueryDoubleText", doubleValue, 1.2,				false );

+		XMLTest( "QueryBoolText", boolValue, true,					false );

+	}

 

 	

 	// ----------- Performance tracking --------------

diff --git a/xmltest.h b/xmltest.h
index 73a48c0..4dd0a51 100755
--- a/xmltest.h
+++ b/xmltest.h
@@ -92,3 +92,38 @@
 	looking for XMLText, not an element, and ToText()

 	is a cast from a Node to a XMLText. 

 */

+

+/** @page Example-4 Read attributes and text information.

+	@dontinclude ./xmltest.cpp

+

+	There are fundamentally 2 ways of writing a key-value

+	pair into an XML file. (Something that's always annoyed

+	me about XML.) Either by using attributes, or by writing

+	the key name into an element and the value into

+	the text node wrapped by the element. Both approaches

+	are illustrated in this example, which shows two ways

+	to encode the value "2" into the key "v":

+

+	@skip example_4

+	@until "</information>";

+

+	TinyXML-2 has accessors for both approaches. 

+

+	When using an attribute, you navigate to the XMLElement

+	with that attribute and use the QueryIntAttribute()

+	group of methods. (Also QueryFloatAttribute(), etc.)

+

+	@skip XMLElement* attributeApproachElement

+	@until &v0 );

+

+	When using the text approach, you need to navigate

+	down one more step to the XMLElement that contains

+	the text. Note the extra FirstChildElement( "v" )

+	in the code below. The value of the text can then

+	be safely queried with the QueryIntText() group

+	of methods. (Also QueryFloatText(), etc.)

+

+	@skip XMLElement* textApproachElement

+	@until &v1 );

+*/

+