new element parsing. reasonable set of test cases.
This commit is contained in:
146
tinyxml2.cpp
146
tinyxml2.cpp
@@ -186,6 +186,7 @@ char* XMLBase::Identify( XMLDocument* document, char* p, XMLNode** node )
|
||||
XMLNode::XMLNode( XMLDocument* doc ) :
|
||||
document( doc ),
|
||||
parent( 0 ),
|
||||
isTextParent( false ),
|
||||
firstChild( 0 ), lastChild( 0 ),
|
||||
prev( 0 ), next( 0 )
|
||||
{
|
||||
@@ -242,6 +243,9 @@ XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
|
||||
addThis->prev = 0;
|
||||
addThis->next = 0;
|
||||
}
|
||||
if ( addThis->ToText() ) {
|
||||
SetTextParent();
|
||||
}
|
||||
return addThis;
|
||||
}
|
||||
|
||||
@@ -254,6 +258,25 @@ void XMLNode::Print( FILE* fp, int depth )
|
||||
}
|
||||
|
||||
|
||||
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 @@ char* XMLText::ParseDeep( char* p )
|
||||
|
||||
void XMLText::Print( FILE* cfile, int depth )
|
||||
{
|
||||
fprintf( cfile, value.GetStr() );
|
||||
const char* v = value.GetStr();
|
||||
fprintf( cfile, v );
|
||||
}
|
||||
|
||||
|
||||
@@ -350,23 +374,10 @@ XMLElement::~XMLElement()
|
||||
}
|
||||
|
||||
|
||||
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 @@ char* XMLElement::ParseDeep( char* p )
|
||||
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 @@ char* XMLElement::ParseDeep( char* p )
|
||||
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 @@ void XMLElement::Print( FILE* cfile, int depth )
|
||||
}
|
||||
|
||||
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 @@ bool XMLDocument::Parse( const char* p )
|
||||
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 );
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user