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