new element parsing. reasonable set of test cases.
diff --git a/tinyxml2.cpp b/tinyxml2.cpp
index 0a02c4b..9df038f 100644
--- a/tinyxml2.cpp
+++ b/tinyxml2.cpp
@@ -186,6 +186,7 @@
XMLNode::XMLNode( XMLDocument* doc ) :
document( doc ),
parent( 0 ),
+ isTextParent( false ),
firstChild( 0 ), lastChild( 0 ),
prev( 0 ), next( 0 )
{
@@ -242,6 +243,9 @@
addThis->prev = 0;
addThis->next = 0;
}
+ if ( addThis->ToText() ) {
+ SetTextParent();
+ }
return addThis;
}
@@ -254,6 +258,25 @@
}
+char* XMLNode::ParseDeep( char* p )
+{
+ while( p && *p ) {
+ XMLNode* node = 0;
+ p = Identify( document, p, &node );
+ if ( p && node ) {
+ p = node->ParseDeep( p );
+ // FIXME: is it the correct closing element?
+ if ( node->IsClosingElement() ) {
+ delete node;
+ return p;
+ }
+ this->InsertEndChild( node );
+ }
+ }
+ return 0;
+}
+
+
void XMLNode::PrintSpace( FILE* fp, int depth )
{
for( int i=0; i<depth; ++i ) {
@@ -276,7 +299,8 @@
void XMLText::Print( FILE* cfile, int depth )
{
- fprintf( cfile, value.GetStr() );
+ const char* v = value.GetStr();
+ fprintf( cfile, v );
}
@@ -350,23 +374,10 @@
}
-char* XMLElement::ParseDeep( char* p )
+char* XMLElement::ParseAttributes( char* p, bool* closedElement )
{
- // Read the element name.
- p = SkipWhiteSpace( p );
- if ( !p ) return 0;
const char* start = p;
-
- // The closing element is the </element> form. It is
- // parsed just like a regular element then deleted from
- // the DOM.
- if ( *p == '/' ) {
- closing = true;
- ++p;
- }
-
- p = ParseName( p, &name );
- if ( name.Empty() ) return 0;
+ *closedElement = false;
// Read the attributes.
while( p ) {
@@ -400,6 +411,7 @@
document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, p );
return 0;
}
+ *closedElement = true;
return p+2; // done; sealed element.
}
// end of the tag
@@ -412,38 +424,47 @@
return 0;
}
}
+ return p;
+}
- while( p && *p ) {
- XMLNode* node = 0;
- p = Identify( document, p, &node );
- if ( p && node ) {
- p = node->ParseDeep( p );
- XMLElement* element = node->ToElement();
- if ( element && element->Closing() ) {
- if ( StringEqual( element->Name(), this->Name() ) ) {
- // All good, this is closing tag.
- delete node;
- }
- else {
- document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, p );
- delete node;
- p = 0;
- }
- return p;
- }
- else {
- this->InsertEndChild( node );
- }
- }
+//
+// <ele></ele>
+// <ele>foo<b>bar</b></ele>
+//
+char* XMLElement::ParseDeep( char* p )
+{
+ // Read the element name.
+ p = SkipWhiteSpace( p );
+ if ( !p ) return 0;
+ const char* start = p;
+
+ // The closing element is the </element> form. It is
+ // parsed just like a regular element then deleted from
+ // the DOM.
+ if ( *p == '/' ) {
+ closing = true;
+ ++p;
}
- return 0;
+
+ p = ParseName( p, &name );
+ if ( name.Empty() ) return 0;
+
+ bool elementClosed=false;
+ p = ParseAttributes( p, &elementClosed );
+ if ( !p || !*p || elementClosed || closing )
+ return p;
+
+ p = XMLNode::ParseDeep( p );
+ return p;
}
void XMLElement::Print( FILE* cfile, int depth )
{
- PrintSpace( cfile, depth );
+ if ( !parent || !parent->IsTextParent() ) {
+ PrintSpace( cfile, depth );
+ }
fprintf( cfile, "<%s", Name() );
for( XMLAttribute* attrib=rootAttribute; attrib; attrib=attrib->next ) {
@@ -452,38 +473,39 @@
}
if ( firstChild ) {
- // fixme: once text is on, it should stay on, and not use newlines.
- bool useNewline = firstChild->ToText() == 0;
-
fprintf( cfile, ">", Name() );
- if ( useNewline ) fprintf( cfile, "\n" );
+ if ( !IsTextParent() ) {
+ fprintf( cfile, "\n" );
+ }
for( XMLNode* node=firstChild; node; node=node->next ) {
node->Print( cfile, depth+1 );
}
- fprintf( cfile, "</%s>\n", Name() );
- // fixme: see note above
- //if ( useNewline ) fprintf( cfile, "\n" );
+ fprintf( cfile, "</%s>", Name() );
+ if ( !IsTextParent() ) {
+ fprintf( cfile, "\n" );
+ }
}
else {
- fprintf( cfile, "/>\n" );
+ fprintf( cfile, "/>" );
+ if ( !IsTextParent() ) {
+ fprintf( cfile, "\n" );
+ }
}
}
// --------- XMLDocument ----------- //
-XMLDocument::XMLDocument() :
+XMLDocument::XMLDocument() :
+ XMLNode( this ),
charBuffer( 0 )
{
- root = new XMLNode( this );
}
XMLDocument::~XMLDocument()
{
- delete root;
- delete charBuffer;
}
@@ -493,25 +515,21 @@
charBuffer = CharBuffer::Construct( p );
XMLNode* node = 0;
- // fixme: clean up
- char* q = Identify( this, charBuffer->mem, &node );
- while ( node ) {
- root->InsertEndChild( node );
- q = node->ParseDeep( q );
- node = 0;
- if ( q && *q ) {
- q = Identify( this, q, &node );
- }
- }
- return false;
+ char* q = ParseDeep( charBuffer->mem );
+ return true;
}
void XMLDocument::Print( FILE* fp, int depth )
{
- for( XMLNode* node = root->firstChild; node; node=node->next ) {
+ for( XMLNode* node = firstChild; node; node=node->next ) {
node->Print( fp, depth );
}
}
+void XMLDocument::SetError( int error, const char* str1, const char* str2 )
+{
+ printf( "ERROR: id=%d '%s' '%s'\n", error, str1, str2 );
+}
+