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 )