Lee Thomason (grinliz) 14 лет назад
Родитель
Сommit
8712757389
4 измененных файлов с 165 добавлено и 5 удалено
  1. 1 1
      dox
  2. 1 2
      readme.txt
  3. 135 2
      tinyxml2.h
  4. 28 0
      xmltest.cpp

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

+ 1 - 2
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.
 
 <h2> What it does. </h2>
 	

+ 135 - 2
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
+	<Document>
+		<Element attributeA = "valueA">
+			<Child attributeB = "value1" />
+			<Child attributeB = "value2" />
+		</Element>
+	<Document>
+	@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

+ 28 - 0
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 = "<element attrib='bar'><sub>Text</sub></element>";
+		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 = "<element attrib='bar'><sub>Text</sub></element>";
+		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 )