new element parsing. reasonable set of test cases.

This commit is contained in:
Lee Thomason 2012-01-24 16:01:51 -08:00
parent 5492a1c705
commit 67d6131d74
4 changed files with 98 additions and 72 deletions

View File

@ -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 );
}

View File

@ -106,7 +106,6 @@ protected:
char* Identify( XMLDocument* document, char* p, XMLNode** node );
};
class XMLNode : public XMLBase
{
friend class XMLDocument;
@ -121,7 +120,12 @@ public:
virtual XMLText* ToText() { return 0; }
virtual XMLComment* ToComment() { return 0; }
virtual char* ParseDeep( char* ) { TIXMLASSERT( 0 ); }
// fixme: guarentee null terminator to avoid internal checks
virtual char* ParseDeep( char* );
void SetTextParent() { isTextParent = true; }
bool IsTextParent() const { return isTextParent; }
virtual bool IsClosingElement() const { return false; }
protected:
XMLNode( XMLDocument* );
@ -129,6 +133,7 @@ protected:
XMLDocument* document;
XMLNode* parent;
bool isTextParent;
XMLNode* firstChild;
XMLNode* lastChild;
@ -208,13 +213,15 @@ public:
virtual void Print( FILE* cfile, int depth );
virtual XMLElement* ToElement() { return this; }
bool Closing() const { return closing; }
virtual bool IsClosingElement() const { return closing; }
char* ParseDeep( char* p );
protected:
private:
char* ParseAttributes( char* p, bool *closedElement );
StrPair name;
bool closing;
XMLAttribute* rootAttribute;
@ -222,7 +229,7 @@ private:
};
class XMLDocument : public XMLBase
class XMLDocument : public XMLNode
{
public:
XMLDocument();
@ -231,20 +238,19 @@ public:
bool Parse( const char* );
void Print( FILE* cfile=stdout, int depth=0 );
/*
XMLNode* Root() { return root; }
XMLNode* RootElement();
*/
enum {
ERROR_ELEMENT_MISMATCH,
ERROR_PARSING_ELEMENT,
ERROR_PARSING_ATTRIBUTE
};
void SetError( int error, const char* str1, const char* str2 ) {}
void SetError( int error, const char* str1, const char* str2 );
private:
XMLDocument( const XMLDocument& ); // intentionally not implemented
XMLNode* root;
CharBuffer* charBuffer;
};

Binary file not shown.

View File

@ -39,6 +39,8 @@ int main( int argc, const char* argv )
"<element attrib1='foo' attrib2=\"bar\" ></element>",
"<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
"<element>Text inside element.</element>",
"<element><b></b></element>",
"<element>Text inside and <b>bolded</b> in the element.</element>",
0
};
for( int i=0; test[i]; ++i ) {