diff --git a/dox b/dox
index 7997ec0..1d40136 100755
--- a/dox
+++ b/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 = 0.9.3
+PROJECT_NUMBER = 0.9.4
# 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/readme.txt b/readme.txt
index 7ac8aa0..29226f7 100755
--- a/readme.txt
+++ b/readme.txt
@@ -11,8 +11,7 @@ github.com/leethomason/tinyxml2
The online HTML version of these docs:
http://grinninglizard.com/tinyxml2docs/index.html
-Where examples are in the "related pages" tab:
-http://grinninglizard.com/tinyxml2docs/pages.html
+Examples are in the "related pages" tab of the HTML docs.
What it does.
diff --git a/tinyxml2.h b/tinyxml2.h
index f6a455d..feffd36 100644
--- a/tinyxml2.h
+++ b/tinyxml2.h
@@ -97,7 +97,7 @@ distribution.
static const int TIXML2_MAJOR_VERSION = 0;
static const int TIXML2_MINOR_VERSION = 9;
-static const int TIXML2_PATCH_VERSION = 3;
+static const int TIXML2_PATCH_VERSION = 4;
namespace tinyxml2
{
@@ -407,7 +407,7 @@ public:
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
+ The type of a XMLNode can be queried, and it can
be cast to its more defined type.
An XMLDocument allocates memory for all its Nodes.
@@ -1132,6 +1132,139 @@ private:
};
+/**
+ A XMLHandle is a class that wraps a node pointer with null checks; this is
+ an incredibly useful thing. Note that XMLHandle is not part of the TinyXML
+ DOM structure. It is a separate utility class.
+
+ Take an example:
+ @verbatim
+
+
+
+
+
+
+ @endverbatim
+
+ Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
+ easy to write a *lot* of code that looks like:
+
+ @verbatim
+ XMLElement* root = document.FirstChildElement( "Document" );
+ if ( root )
+ {
+ XMLElement* element = root->FirstChildElement( "Element" );
+ if ( element )
+ {
+ XMLElement* child = element->FirstChildElement( "Child" );
+ if ( child )
+ {
+ XMLElement* child2 = child->NextSiblingElement( "Child" );
+ if ( child2 )
+ {
+ // Finally do something useful.
+ @endverbatim
+
+ And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
+ of such code. A XMLHandle checks for null pointers so it is perfectly safe
+ and correct to use:
+
+ @verbatim
+ XMLHandle docHandle( &document );
+ XMLElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild().NextSibling().ToElement();
+ if ( child2 )
+ {
+ // do something useful
+ @endverbatim
+
+ Which is MUCH more concise and useful.
+
+ It is also safe to copy handles - internally they are nothing more than node pointers.
+ @verbatim
+ XMLHandle handleCopy = handle;
+ @endverbatim
+
+ See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
+*/
+class XMLHandle
+{
+public:
+ /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
+ XMLHandle( XMLNode* _node ) { node = _node; }
+ /// Create a handle from a node.
+ XMLHandle( XMLNode& _node ) { node = &_node; }
+ /// Copy constructor
+ XMLHandle( const XMLHandle& ref ) { node = ref.node; }
+ /// Assignment
+ XMLHandle operator=( const XMLHandle& ref ) { node = ref.node; return *this; }
+
+ /// Get the first child of this handle.
+ XMLHandle FirstChild() { return XMLHandle( node ? node->FirstChild() : 0 ); }
+ /// Get the first child element of this handle.
+ XMLHandle FirstChildElement( const char* value=0 ) { return XMLHandle( node ? node->FirstChildElement( value ) : 0 ); }
+ /// Get the last child of this handle.
+ XMLHandle LastChild() { return XMLHandle( node ? node->LastChild() : 0 ); }
+ /// Get the last child element of this handle.
+ XMLHandle LastChildElement( const char* _value=0 ) { return XMLHandle( node ? node->LastChildElement( _value ) : 0 ); }
+ /// Get the previous sibling of this handle.
+ XMLHandle PreviousSibling() { return XMLHandle( node ? node->PreviousSibling() : 0 ); }
+ /// Get the previous sibling element of this handle.
+ XMLHandle PreviousSiblingElement( const char* _value=0 ) { return XMLHandle( node ? node->PreviousSiblingElement( _value ) : 0 ); }
+ /// Get the next sibling of this handle.
+ XMLHandle NextSibling() { return XMLHandle( node ? node->NextSibling() : 0 ); }
+ /// Get the next sibling element of this handle.
+ XMLHandle NextSiblingElement( const char* _value=0 ) { return XMLHandle( node ? node->NextSiblingElement( _value ) : 0 ); }
+
+ /// Safe cast to XMLNode. This can return null.
+ XMLNode* ToNode() { return node; }
+ /// Safe cast to XMLElement. This can return null.
+ XMLElement* ToElement() { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
+ /// Safe cast to XMLText. This can return null.
+ XMLText* ToText() { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
+ /// Safe cast to XMLUnknown. This can return null.
+ XMLUnknown* ToUnknown() { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
+ /// Safe cast to XMLDeclaration. This can return null.
+ XMLDeclaration* ToDeclaration() { return ( ( node && node->ToDeclaration() ) ? node->ToDeclaration() : 0 ); }
+
+private:
+ XMLNode* node;
+};
+
+
+/**
+ A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the
+ same in all regards, except for the 'const' qualifiers. See XMLHandle for API.
+*/
+class XMLConstHandle
+{
+public:
+ XMLConstHandle( const XMLNode* _node ) { node = _node; }
+ XMLConstHandle( const XMLNode& _node ) { node = &_node; }
+ XMLConstHandle( const XMLConstHandle& ref ) { node = ref.node; }
+
+ XMLConstHandle operator=( const XMLConstHandle& ref ) { node = ref.node; return *this; }
+
+ const XMLConstHandle FirstChild() const { return XMLConstHandle( node ? node->FirstChild() : 0 ); }
+ const XMLConstHandle FirstChildElement( const char* value=0 ) const { return XMLConstHandle( node ? node->FirstChildElement( value ) : 0 ); }
+ const XMLConstHandle LastChild() const { return XMLConstHandle( node ? node->LastChild() : 0 ); }
+ const XMLConstHandle LastChildElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->LastChildElement( _value ) : 0 ); }
+ const XMLConstHandle PreviousSibling() const { return XMLConstHandle( node ? node->PreviousSibling() : 0 ); }
+ const XMLConstHandle PreviousSiblingElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->PreviousSiblingElement( _value ) : 0 ); }
+ const XMLConstHandle NextSibling() const { return XMLConstHandle( node ? node->NextSibling() : 0 ); }
+ const XMLConstHandle NextSiblingElement( const char* _value=0 ) const { return XMLConstHandle( node ? node->NextSiblingElement( _value ) : 0 ); }
+
+
+ const XMLNode* ToNode() const { return node; }
+ const XMLElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
+ const XMLText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
+ const XMLUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
+ const XMLDeclaration* ToDeclaration() const { return ( ( node && node->ToDeclaration() ) ? node->ToDeclaration() : 0 ); }
+
+private:
+ const XMLNode* node;
+};
+
/**
Printing functionality. The XMLPrinter gives you more
diff --git a/xmltest.cpp b/xmltest.cpp
index 29809e8..5e48d50 100644
--- a/xmltest.cpp
+++ b/xmltest.cpp
@@ -761,6 +761,34 @@ int main( int /*argc*/, const char ** /*argv*/ )
XMLTest( "Error in snprinf handling.", true, doc.Error() );
}
+ // -------- Handles ------------
+ {
+ static const char* xml = "Text";
+ XMLDocument doc;
+ doc.Parse( xml );
+
+ XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
+ XMLTest( "Handle, success, mutable", ele->Value(), "sub" );
+
+ XMLHandle docH( doc );
+ ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
+ XMLTest( "Handle, dne, mutable", 0, (int)ele );
+ }
+
+ {
+ static const char* xml = "Text";
+ XMLDocument doc;
+ doc.Parse( xml );
+ XMLConstHandle docH( doc );
+
+ const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
+ XMLTest( "Handle, success, const", ele->Value(), "sub" );
+
+ ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
+ XMLTest( "Handle, dne, const", 0, (int)ele );
+ }
+
+
// ----------- Performance tracking --------------
{
#if defined( _MSC_VER )