Explorar el Código

Moving string in/out into XMLUtil. Using that across the API. Supporting text queries of primitive types.

Lee Thomason hace 13 años
padre
commit
21be882810
Se han modificado 6 ficheros con 382 adiciones y 43 borrados
  1. 1 1
      CMakeLists.txt
  2. 1 1
      dox
  3. 201 24
      tinyxml2.cpp
  4. 70 6
      tinyxml2.h
  5. 74 11
      xmltest.cpp
  6. 35 0
      xmltest.h

+ 1 - 1
CMakeLists.txt

@@ -10,7 +10,7 @@ include(GNUInstallDirs)
 ################################
 # set lib version here
 
-set(GENERIC_LIB_VERSION "1.0.5")
+set(GENERIC_LIB_VERSION "1.0.6")
 set(GENERIC_LIB_SOVERSION "1")
 
 

+ 1 - 1
dox

@@ -32,7 +32,7 @@ PROJECT_NAME           = "TinyXML-2"
 # 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

+ 201 - 24
tinyxml2.cpp

@@ -369,6 +369,86 @@ const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
 }
 
 
+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 @@ void XMLAttribute::SetName( const char* n )
 
 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::QueryIntValue( int* value ) const
 
 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::QueryUnsignedValue( unsigned int* value ) const
 
 int XMLAttribute::QueryBoolValue( bool* value ) const
 {
-	int ival = -1;
-	QueryIntValue( &ival );
-
-	if ( ival > 0 || XMLUtil::StringEqual( Value(), "true" ) ) {
-		*value = true;
-		return XML_NO_ERROR;
-	}
-	else if ( ival == 0 || XMLUtil::StringEqual( Value(), "false" ) ) {
-		*value = false;
+	if ( XMLUtil::ToBool( Value(), value )) {
 		return XML_NO_ERROR;
 	}
 	return XML_WRONG_ATTRIBUTE_TYPE;
 }
 
 
-int XMLAttribute::QueryDoubleValue( double* value ) const
+int XMLAttribute::QueryFloatValue( float* value ) const
 {
-	if ( TIXML_SSCANF( Value(), "%lf", value ) == 1 )
+	if ( XMLUtil::ToFloat( Value(), value ))
 		return XML_NO_ERROR;
 	return XML_WRONG_ATTRIBUTE_TYPE;
 }
 
 
-int XMLAttribute::QueryFloatValue( float* value ) const
+int XMLAttribute::QueryDoubleValue( double* value ) const
 {
-	if ( TIXML_SSCANF( Value(), "%f", value ) == 1 )
+	if ( XMLUtil::ToDouble( Value(), value ))
 		return XML_NO_ERROR;
 	return XML_WRONG_ATTRIBUTE_TYPE;
 }
@@ -998,7 +1070,7 @@ void XMLAttribute::SetAttribute( const char* v )
 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( int v )
 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( unsigned v )
 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 @@ const char* XMLElement::GetText() const
 }
 
 
+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, const char* value )
 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, int v )
 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, unsigned v )
 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, bool v )
 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( const char* text, bool cdata )
 	}
 }
 
+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 )
 {

+ 70 - 6
tinyxml2.h

@@ -85,7 +85,7 @@ distribution.
 
 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 @@ public:
 	// 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 @@ enum {
 	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 @@ public:
 		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 @@ public:
 		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 @@ public:
 
 	/// 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 );

+ 74 - 11
xmltest.cpp

@@ -38,7 +38,7 @@ bool XMLTest (const char* testString, const char* expected, const char* found, b
 }
 
 
-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 @@ int example_3()
 }
 
 
+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 @@ int main( int /*argc*/, const char ** /*argv*/ )
 	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 @@ int main( int /*argc*/, const char ** /*argv*/ )
 		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 @@ int main( int /*argc*/, const char ** /*argv*/ )
 
 		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 @@ int main( int /*argc*/, const char ** /*argv*/ )
 		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 @@ int main( int /*argc*/, const char ** /*argv*/ )
 
 		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 @@ int main( int /*argc*/, const char ** /*argv*/ )
 		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 @@ int main( int /*argc*/, const char ** /*argv*/ )
 		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 @@ int main( int /*argc*/, const char ** /*argv*/ )
 		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 @@ int main( int /*argc*/, const char ** /*argv*/ )
 		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 --------------

+ 35 - 0
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 );
+*/
+