mirror of https://github.com/AxioDL/tinyxml2.git
pulled out streamer class.
This commit is contained in:
parent
67d6131d74
commit
5cae897775
186
tinyxml2.cpp
186
tinyxml2.cpp
|
@ -250,10 +250,10 @@ XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void XMLNode::Print( FILE* fp, int depth )
|
void XMLNode::Print( XMLStreamer* streamer )
|
||||||
{
|
{
|
||||||
for( XMLNode* node = firstChild; node; node=node->next ) {
|
for( XMLNode* node = firstChild; node; node=node->next ) {
|
||||||
node->Print( fp, depth );
|
node->Print( streamer );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,14 +276,14 @@ char* XMLNode::ParseDeep( char* p )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
void XMLNode::PrintSpace( FILE* fp, int depth )
|
void XMLNode::PrintSpace( FILE* fp, int depth )
|
||||||
{
|
{
|
||||||
for( int i=0; i<depth; ++i ) {
|
for( int i=0; i<depth; ++i ) {
|
||||||
fprintf( fp, " " );
|
fprintf( fp, " " );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// --------- XMLText ---------- //
|
// --------- XMLText ---------- //
|
||||||
char* XMLText::ParseDeep( char* p )
|
char* XMLText::ParseDeep( char* p )
|
||||||
|
@ -297,10 +297,10 @@ char* XMLText::ParseDeep( char* p )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void XMLText::Print( FILE* cfile, int depth )
|
void XMLText::Print( XMLStreamer* streamer )
|
||||||
{
|
{
|
||||||
const char* v = value.GetStr();
|
const char* v = value.GetStr();
|
||||||
fprintf( cfile, v );
|
streamer->PushText( v );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -317,10 +317,11 @@ XMLComment::~XMLComment()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void XMLComment::Print( FILE* fp, int depth )
|
void XMLComment::Print( XMLStreamer* streamer )
|
||||||
{
|
{
|
||||||
XMLNode::Print( fp, depth );
|
// XMLNode::Print( fp, depth );
|
||||||
fprintf( fp, "<!--%s-->\n", value.GetStr() );
|
// fprintf( fp, "<!--%s-->\n", value.GetStr() );
|
||||||
|
streamer->PushComment( value.GetStr() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -345,10 +346,11 @@ char* XMLAttribute::ParseDeep( char* p )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void XMLAttribute::Print( FILE* cfile )
|
void XMLAttribute::Print( XMLStreamer* streamer )
|
||||||
{
|
{
|
||||||
// fixme: sort out single vs. double quote
|
// fixme: sort out single vs. double quote
|
||||||
fprintf( cfile, "%s=\"%s\"", name.GetStr(), value.GetStr() );
|
//fprintf( cfile, "%s=\"%s\"", name.GetStr(), value.GetStr() );
|
||||||
|
streamer->PushAttribute( name.GetStr(), value.GetStr() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -460,19 +462,26 @@ char* XMLElement::ParseDeep( char* p )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void XMLElement::Print( FILE* cfile, int depth )
|
void XMLElement::Print( XMLStreamer* streamer )
|
||||||
{
|
{
|
||||||
if ( !parent || !parent->IsTextParent() ) {
|
//if ( !parent || !parent->IsTextParent() ) {
|
||||||
PrintSpace( cfile, depth );
|
// PrintSpace( cfile, depth );
|
||||||
}
|
//}
|
||||||
fprintf( cfile, "<%s", Name() );
|
//fprintf( cfile, "<%s", Name() );
|
||||||
|
streamer->OpenElement( Name(), IsTextParent() );
|
||||||
|
|
||||||
for( XMLAttribute* attrib=rootAttribute; attrib; attrib=attrib->next ) {
|
for( XMLAttribute* attrib=rootAttribute; attrib; attrib=attrib->next ) {
|
||||||
fprintf( cfile, " " );
|
//fprintf( cfile, " " );
|
||||||
attrib->Print( cfile );
|
attrib->Print( streamer );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( firstChild ) {
|
for( XMLNode* node=firstChild; node; node=node->next ) {
|
||||||
|
node->Print( streamer );
|
||||||
|
}
|
||||||
|
streamer->CloseElement();
|
||||||
|
|
||||||
|
/* if ( firstChild ) {
|
||||||
fprintf( cfile, ">", Name() );
|
fprintf( cfile, ">", Name() );
|
||||||
if ( !IsTextParent() ) {
|
if ( !IsTextParent() ) {
|
||||||
fprintf( cfile, "\n" );
|
fprintf( cfile, "\n" );
|
||||||
|
@ -492,7 +501,7 @@ void XMLElement::Print( FILE* cfile, int depth )
|
||||||
if ( !IsTextParent() ) {
|
if ( !IsTextParent() ) {
|
||||||
fprintf( cfile, "\n" );
|
fprintf( cfile, "\n" );
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -520,10 +529,13 @@ bool XMLDocument::Parse( const char* p )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void XMLDocument::Print( FILE* fp, int depth )
|
void XMLDocument::Print( XMLStreamer* streamer )
|
||||||
{
|
{
|
||||||
|
XMLStreamer stdStreamer( stdout );
|
||||||
|
if ( !streamer )
|
||||||
|
streamer = &stdStreamer;
|
||||||
for( XMLNode* node = firstChild; node; node=node->next ) {
|
for( XMLNode* node = firstChild; node; node=node->next ) {
|
||||||
node->Print( fp, depth );
|
node->Print( streamer );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,3 +545,133 @@ void XMLDocument::SetError( int error, const char* str1, const char* str2 )
|
||||||
printf( "ERROR: id=%d '%s' '%s'\n", error, str1, str2 );
|
printf( "ERROR: id=%d '%s' '%s'\n", error, str1, str2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
StringStack::StringStack()
|
||||||
|
{
|
||||||
|
mem = new char[INIT];
|
||||||
|
*mem = 0;
|
||||||
|
inUse = 1; // always has a null
|
||||||
|
allocated = INIT;
|
||||||
|
nPositive = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void StringStack::Push( const char* str ) {
|
||||||
|
int needed = strlen( str ) + 1;
|
||||||
|
if ( needed > 1 )
|
||||||
|
nPositive++;
|
||||||
|
if ( inUse+needed > allocated ) {
|
||||||
|
// fixme: power of 2
|
||||||
|
// less stupid allocation
|
||||||
|
int more = inUse+needed + 1000;
|
||||||
|
|
||||||
|
char* newMem = new char[more];
|
||||||
|
memcpy( newMem, mem, inUse );
|
||||||
|
delete [] mem;
|
||||||
|
mem = newMem;
|
||||||
|
}
|
||||||
|
strcpy( mem+inUse, str );
|
||||||
|
inUse += needed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char* StringStack::Pop() {
|
||||||
|
TIXMLASSERT( inUse > 1 );
|
||||||
|
const char* p = mem+inUse-2;
|
||||||
|
if ( *p ) {
|
||||||
|
nPositive--;
|
||||||
|
}
|
||||||
|
while( *p ) { // stack starts with a null, don't need to check for 'mem'
|
||||||
|
TIXMLASSERT( p > mem );
|
||||||
|
--p;
|
||||||
|
}
|
||||||
|
inUse = p-mem+1;
|
||||||
|
return p+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
XMLStreamer::XMLStreamer( FILE* file ) : fp( file ), depth( 0 ), elementJustOpened( false )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void XMLStreamer::PrintSpace( int depth )
|
||||||
|
{
|
||||||
|
for( int i=0; i<depth; ++i ) {
|
||||||
|
fprintf( fp, " " );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void XMLStreamer::OpenElement( const char* name, bool textParent )
|
||||||
|
{
|
||||||
|
if ( elementJustOpened ) {
|
||||||
|
SealElement();
|
||||||
|
}
|
||||||
|
stack.Push( name );
|
||||||
|
text.Push( textParent ? "T" : "" );
|
||||||
|
|
||||||
|
PrintSpace( depth );
|
||||||
|
fprintf( fp, "<%s", name );
|
||||||
|
elementJustOpened = true;
|
||||||
|
++depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void XMLStreamer::PushAttribute( const char* name, const char* value )
|
||||||
|
{
|
||||||
|
TIXMLASSERT( elementJustOpened );
|
||||||
|
fprintf( fp, " %s=\"%s\"", name, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void XMLStreamer::CloseElement()
|
||||||
|
{
|
||||||
|
--depth;
|
||||||
|
const char* name = stack.Pop();
|
||||||
|
text.Pop();
|
||||||
|
|
||||||
|
if ( elementJustOpened ) {
|
||||||
|
fprintf( fp, "/>" );
|
||||||
|
if ( text.NumPositive() == 0 ) {
|
||||||
|
fprintf( fp, "\n" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PrintSpace( depth );
|
||||||
|
fprintf( fp, "</%s>", name );
|
||||||
|
if ( text.NumPositive() == 0 ) {
|
||||||
|
fprintf( fp, "\n" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elementJustOpened = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void XMLStreamer::SealElement()
|
||||||
|
{
|
||||||
|
elementJustOpened = false;
|
||||||
|
fprintf( fp, ">" );
|
||||||
|
if ( text.NumPositive() == 0 ) {
|
||||||
|
fprintf( fp, "\n" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void XMLStreamer::PushText( const char* text )
|
||||||
|
{
|
||||||
|
if ( elementJustOpened ) {
|
||||||
|
SealElement();
|
||||||
|
}
|
||||||
|
fprintf( fp, "%s", text );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void XMLStreamer::PushComment( const char* comment )
|
||||||
|
{
|
||||||
|
if ( elementJustOpened ) {
|
||||||
|
SealElement();
|
||||||
|
}
|
||||||
|
PrintSpace( depth );
|
||||||
|
fprintf( fp, "<!--%s-->\n", comment );
|
||||||
|
}
|
||||||
|
|
65
tinyxml2.h
65
tinyxml2.h
|
@ -36,6 +36,8 @@ class XMLComment;
|
||||||
class XMLNode;
|
class XMLNode;
|
||||||
class XMLText;
|
class XMLText;
|
||||||
|
|
||||||
|
class XMLStreamer;
|
||||||
|
|
||||||
// internal - move to separate namespace
|
// internal - move to separate namespace
|
||||||
struct CharBuffer
|
struct CharBuffer
|
||||||
{
|
{
|
||||||
|
@ -106,6 +108,7 @@ protected:
|
||||||
char* Identify( XMLDocument* document, char* p, XMLNode** node );
|
char* Identify( XMLDocument* document, char* p, XMLNode** node );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class XMLNode : public XMLBase
|
class XMLNode : public XMLBase
|
||||||
{
|
{
|
||||||
friend class XMLDocument;
|
friend class XMLDocument;
|
||||||
|
@ -114,7 +117,7 @@ public:
|
||||||
virtual ~XMLNode();
|
virtual ~XMLNode();
|
||||||
|
|
||||||
XMLNode* InsertEndChild( XMLNode* addThis );
|
XMLNode* InsertEndChild( XMLNode* addThis );
|
||||||
virtual void Print( FILE* cfile, int depth );
|
virtual void Print( XMLStreamer* streamer );
|
||||||
|
|
||||||
virtual XMLElement* ToElement() { return 0; }
|
virtual XMLElement* ToElement() { return 0; }
|
||||||
virtual XMLText* ToText() { return 0; }
|
virtual XMLText* ToText() { return 0; }
|
||||||
|
@ -142,8 +145,6 @@ protected:
|
||||||
XMLNode* next;
|
XMLNode* next;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void PrintSpace( FILE* cfile, int depth ); // prints leading spaces.
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -153,7 +154,7 @@ public:
|
||||||
XMLText( XMLDocument* doc ) : XMLNode( doc ) {}
|
XMLText( XMLDocument* doc ) : XMLNode( doc ) {}
|
||||||
virtual ~XMLText() {}
|
virtual ~XMLText() {}
|
||||||
|
|
||||||
virtual void Print( FILE* cfile, int depth );
|
virtual void Print( XMLStreamer* streamer );
|
||||||
const char* Value() { return value.GetStr(); }
|
const char* Value() { return value.GetStr(); }
|
||||||
virtual XMLText* ToText() { return this; }
|
virtual XMLText* ToText() { return this; }
|
||||||
|
|
||||||
|
@ -172,7 +173,7 @@ public:
|
||||||
XMLComment( XMLDocument* doc );
|
XMLComment( XMLDocument* doc );
|
||||||
virtual ~XMLComment();
|
virtual ~XMLComment();
|
||||||
|
|
||||||
virtual void Print( FILE* cfile, int depth );
|
virtual void Print( XMLStreamer* );
|
||||||
virtual XMLComment* ToComment() { return this; }
|
virtual XMLComment* ToComment() { return this; }
|
||||||
|
|
||||||
const char* Value() { return value.GetStr(); }
|
const char* Value() { return value.GetStr(); }
|
||||||
|
@ -192,7 +193,7 @@ class XMLAttribute : public XMLBase
|
||||||
public:
|
public:
|
||||||
XMLAttribute( XMLElement* element ) : next( 0 ) {}
|
XMLAttribute( XMLElement* element ) : next( 0 ) {}
|
||||||
virtual ~XMLAttribute() {}
|
virtual ~XMLAttribute() {}
|
||||||
virtual void Print( FILE* cfile );
|
virtual void Print( XMLStreamer* streamer );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char* ParseDeep( char* p );
|
char* ParseDeep( char* p );
|
||||||
|
@ -210,7 +211,7 @@ public:
|
||||||
virtual ~XMLElement();
|
virtual ~XMLElement();
|
||||||
|
|
||||||
const char* Name() { return name.GetStr(); }
|
const char* Name() { return name.GetStr(); }
|
||||||
virtual void Print( FILE* cfile, int depth );
|
virtual void Print( XMLStreamer* );
|
||||||
|
|
||||||
virtual XMLElement* ToElement() { return this; }
|
virtual XMLElement* ToElement() { return this; }
|
||||||
virtual bool IsClosingElement() const { return closing; }
|
virtual bool IsClosingElement() const { return closing; }
|
||||||
|
@ -236,7 +237,7 @@ public:
|
||||||
~XMLDocument();
|
~XMLDocument();
|
||||||
|
|
||||||
bool Parse( const char* );
|
bool Parse( const char* );
|
||||||
void Print( FILE* cfile=stdout, int depth=0 );
|
void Print( XMLStreamer* streamer=0 );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
XMLNode* Root() { return root; }
|
XMLNode* Root() { return root; }
|
||||||
|
@ -255,6 +256,54 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class StringStack
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StringStack();
|
||||||
|
~StringStack() { delete[] mem; }
|
||||||
|
|
||||||
|
void Push( const char* str );
|
||||||
|
const char* Pop();
|
||||||
|
|
||||||
|
int NumPositive() const { return nPositive; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum {
|
||||||
|
INIT=10 // fixme, super small for testing
|
||||||
|
};
|
||||||
|
char* mem;
|
||||||
|
int inUse; // includes null
|
||||||
|
int allocated; // bytes allocated
|
||||||
|
int nPositive; // number of strings with len > 0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class XMLStreamer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
XMLStreamer( FILE* file );
|
||||||
|
~XMLStreamer() {}
|
||||||
|
|
||||||
|
void OpenElement( const char* name, bool textParent );
|
||||||
|
void PushAttribute( const char* name, const char* value );
|
||||||
|
void CloseElement();
|
||||||
|
|
||||||
|
void PushText( const char* text );
|
||||||
|
void PushComment( const char* comment );
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SealElement();
|
||||||
|
void PrintSpace( int depth );
|
||||||
|
|
||||||
|
FILE* fp;
|
||||||
|
int depth;
|
||||||
|
bool elementJustOpened;
|
||||||
|
|
||||||
|
StringStack stack;
|
||||||
|
StringStack text;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
}; // tinyxml2
|
}; // tinyxml2
|
||||||
|
|
||||||
|
|
||||||
|
|
19
xmltest.cpp
19
xmltest.cpp
|
@ -28,25 +28,24 @@ int main( int argc, const char* argv )
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
static const char* test[] = { //"<!--single element-->",
|
static const char* test[] = { //"<element />",
|
||||||
"<element />",
|
//"<element></element>",
|
||||||
"<element></element>",
|
//"<element><subelement/></element>",
|
||||||
//"<!--single sub-element-->",
|
//"<element><subelement></subelement></element>",
|
||||||
"<element><subelement/></element>",
|
"<element><subelement><subsub/></subelement></element>",
|
||||||
"<element><subelement></subelement></element>",
|
|
||||||
"<!--comment beside elements--><element><subelement></subelement></element>",
|
"<!--comment beside elements--><element><subelement></subelement></element>",
|
||||||
"<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
|
//"<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
|
||||||
"<element attrib1='foo' attrib2=\"bar\" ></element>",
|
"<element attrib1='foo' attrib2=\"bar\" ></element>",
|
||||||
"<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
|
"<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
|
||||||
"<element>Text inside element.</element>",
|
//"<element>Text inside element.</element>",
|
||||||
"<element><b></b></element>",
|
//"<element><b></b></element>",
|
||||||
"<element>Text inside and <b>bolded</b> in the element.</element>",
|
"<element>Text inside and <b>bolded</b> in the element.</element>",
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
for( int i=0; test[i]; ++i ) {
|
for( int i=0; test[i]; ++i ) {
|
||||||
XMLDocument doc;
|
XMLDocument doc;
|
||||||
doc.Parse( test[i] );
|
doc.Parse( test[i] );
|
||||||
doc.Print( stdout );
|
doc.Print();
|
||||||
printf( "----------------------------------------------\n" );
|
printf( "----------------------------------------------\n" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue