mirror of https://github.com/AxioDL/tinyxml2.git
improved the streamer interface so it doesn't require text parent. now possible to connect visitor and streamer.
This commit is contained in:
parent
43f59307cc
commit
56bdd0259e
140
tinyxml2.cpp
140
tinyxml2.cpp
|
@ -128,9 +128,9 @@ const char* StringPool::Intern( const char* str )
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
// --------- XMLBase ----------- //
|
// --------- XMLUtil ----------- //
|
||||||
|
|
||||||
char* XMLBase::ParseText( char* p, StrPair* pair, const char* endTag, int strFlags )
|
char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
|
||||||
{
|
{
|
||||||
TIXMLASSERT( endTag && *endTag );
|
TIXMLASSERT( endTag && *endTag );
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ char* XMLBase::ParseText( char* p, StrPair* pair, const char* endTag, int strFla
|
||||||
// Inner loop of text parsing.
|
// Inner loop of text parsing.
|
||||||
while ( *p ) {
|
while ( *p ) {
|
||||||
if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
|
if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
|
||||||
pair->Set( start, p, strFlags );
|
Set( start, p, strFlags );
|
||||||
return p + length;
|
return p + length;
|
||||||
}
|
}
|
||||||
++p;
|
++p;
|
||||||
|
@ -150,7 +150,7 @@ char* XMLBase::ParseText( char* p, StrPair* pair, const char* endTag, int strFla
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char* XMLBase::ParseName( char* p, StrPair* pair )
|
char* StrPair::ParseName( char* p )
|
||||||
{
|
{
|
||||||
char* start = p;
|
char* start = p;
|
||||||
|
|
||||||
|
@ -159,12 +159,12 @@ char* XMLBase::ParseName( char* p, StrPair* pair )
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !IsAlpha( *p ) ) {
|
if ( !XMLUtil::IsAlpha( *p ) ) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
while( *p && (
|
while( *p && (
|
||||||
IsAlphaNum( (unsigned char) *p )
|
XMLUtil::IsAlphaNum( (unsigned char) *p )
|
||||||
|| *p == '_'
|
|| *p == '_'
|
||||||
|| *p == '-'
|
|| *p == '-'
|
||||||
|| *p == '.'
|
|| *p == '.'
|
||||||
|
@ -174,7 +174,7 @@ char* XMLBase::ParseName( char* p, StrPair* pair )
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( p > start ) {
|
if ( p > start ) {
|
||||||
pair->Set( start, p, 0 );
|
Set( start, p, 0 );
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -185,7 +185,7 @@ char* XMLDocument::Identify( char* p, XMLNode** node )
|
||||||
{
|
{
|
||||||
XMLNode* returnNode = 0;
|
XMLNode* returnNode = 0;
|
||||||
char* start = p;
|
char* start = p;
|
||||||
p = XMLBase::SkipWhiteSpace( p );
|
p = XMLUtil::SkipWhiteSpace( p );
|
||||||
if( !p || !*p )
|
if( !p || !*p )
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -210,18 +210,18 @@ char* XMLDocument::Identify( char* p, XMLNode** node )
|
||||||
static const int cdataHeaderLen = 9;
|
static const int cdataHeaderLen = 9;
|
||||||
static const int elementHeaderLen = 1;
|
static const int elementHeaderLen = 1;
|
||||||
|
|
||||||
if ( XMLBase::StringEqual( p, commentHeader, commentHeaderLen ) ) {
|
if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
|
||||||
returnNode = new (commentPool.Alloc()) XMLComment( this );
|
returnNode = new (commentPool.Alloc()) XMLComment( this );
|
||||||
returnNode->memPool = &commentPool;
|
returnNode->memPool = &commentPool;
|
||||||
p += commentHeaderLen;
|
p += commentHeaderLen;
|
||||||
}
|
}
|
||||||
else if ( XMLBase::StringEqual( p, elementHeader, elementHeaderLen ) ) {
|
else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
|
||||||
returnNode = new (elementPool.Alloc()) XMLElement( this );
|
returnNode = new (elementPool.Alloc()) XMLElement( this );
|
||||||
returnNode->memPool = &elementPool;
|
returnNode->memPool = &elementPool;
|
||||||
p += elementHeaderLen;
|
p += elementHeaderLen;
|
||||||
}
|
}
|
||||||
// fixme: better text detection
|
// fixme: better text detection
|
||||||
else if ( (*p != '<') && XMLBase::IsAlphaNum( *p ) ) {
|
else if ( (*p != '<') && XMLUtil::IsAlphaNum( *p ) ) {
|
||||||
returnNode = new (textPool.Alloc()) XMLText( this );
|
returnNode = new (textPool.Alloc()) XMLText( this );
|
||||||
returnNode->memPool = &textPool;
|
returnNode->memPool = &textPool;
|
||||||
p = start; // Back it up, all the text counts.
|
p = start; // Back it up, all the text counts.
|
||||||
|
@ -235,6 +235,20 @@ char* XMLDocument::Identify( char* p, XMLNode** node )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool XMLDocument::Accept( XMLVisitor* visitor ) const
|
||||||
|
{
|
||||||
|
if ( visitor->VisitEnter( *this ) )
|
||||||
|
{
|
||||||
|
for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
|
||||||
|
{
|
||||||
|
if ( !node->Accept( visitor ) )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return visitor->VisitExit( *this );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// --------- XMLNode ----------- //
|
// --------- XMLNode ----------- //
|
||||||
|
|
||||||
XMLNode::XMLNode( XMLDocument* doc ) :
|
XMLNode::XMLNode( XMLDocument* doc ) :
|
||||||
|
@ -314,12 +328,12 @@ XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
XMLElement* XMLNode::FirstChildElement( const char* value )
|
const XMLElement* XMLNode::FirstChildElement( const char* value ) const
|
||||||
{
|
{
|
||||||
for( XMLNode* node=firstChild; node; node=node->next ) {
|
for( XMLNode* node=firstChild; node; node=node->next ) {
|
||||||
XMLElement* element = node->ToElement();
|
XMLElement* element = node->ToElement();
|
||||||
if ( element ) {
|
if ( element ) {
|
||||||
if ( !value || XMLBase::StringEqual( element->Name(), value ) ) {
|
if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -328,6 +342,27 @@ XMLElement* XMLNode::FirstChildElement( const char* value )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const XMLElement* XMLNode::LastChildElement( const char* value ) const
|
||||||
|
{
|
||||||
|
for( XMLNode* node=lastChild; node; node=node->prev ) {
|
||||||
|
XMLElement* element = node->ToElement();
|
||||||
|
if ( element ) {
|
||||||
|
if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void XMLNode::DeleteChild( XMLNode* node )
|
||||||
|
{
|
||||||
|
TIXMLASSERT( node->parent == this );
|
||||||
|
TIXMLASSERT( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void XMLNode::Print( XMLStreamer* streamer )
|
void XMLNode::Print( XMLStreamer* streamer )
|
||||||
{
|
{
|
||||||
for( XMLNode* node = firstChild; node; node=node->next ) {
|
for( XMLNode* node = firstChild; node; node=node->next ) {
|
||||||
|
@ -357,7 +392,7 @@ char* XMLNode::ParseDeep( char* p )
|
||||||
// --------- XMLText ---------- //
|
// --------- XMLText ---------- //
|
||||||
char* XMLText::ParseDeep( char* p )
|
char* XMLText::ParseDeep( char* p )
|
||||||
{
|
{
|
||||||
p = XMLBase::ParseText( p, &value, "<", StrPair::TEXT_ELEMENT );
|
p = value.ParseText( p, "<", StrPair::TEXT_ELEMENT );
|
||||||
// consumes the end tag.
|
// consumes the end tag.
|
||||||
if ( p && *p ) {
|
if ( p && *p ) {
|
||||||
return p-1;
|
return p-1;
|
||||||
|
@ -373,6 +408,12 @@ void XMLText::Print( XMLStreamer* streamer )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool XMLText::Accept( XMLVisitor* visitor ) const
|
||||||
|
{
|
||||||
|
return visitor->Visit( *this );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// --------- XMLComment ---------- //
|
// --------- XMLComment ---------- //
|
||||||
|
|
||||||
XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
|
XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
|
||||||
|
@ -397,19 +438,25 @@ void XMLComment::Print( XMLStreamer* streamer )
|
||||||
char* XMLComment::ParseDeep( char* p )
|
char* XMLComment::ParseDeep( char* p )
|
||||||
{
|
{
|
||||||
// Comment parses as text.
|
// Comment parses as text.
|
||||||
return XMLBase::ParseText( p, &value, "-->", StrPair::COMMENT );
|
return value.ParseText( p, "-->", StrPair::COMMENT );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool XMLComment::Accept( XMLVisitor* visitor ) const
|
||||||
|
{
|
||||||
|
return visitor->Visit( *this );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// --------- XMLAttribute ---------- //
|
// --------- XMLAttribute ---------- //
|
||||||
char* XMLAttribute::ParseDeep( char* p )
|
char* XMLAttribute::ParseDeep( char* p )
|
||||||
{
|
{
|
||||||
p = XMLBase::ParseText( p, &name, "=", StrPair::ATTRIBUTE_NAME );
|
p = name.ParseText( p, "=", StrPair::ATTRIBUTE_NAME );
|
||||||
if ( !p || !*p ) return 0;
|
if ( !p || !*p ) return 0;
|
||||||
|
|
||||||
char endTag[2] = { *p, 0 };
|
char endTag[2] = { *p, 0 };
|
||||||
++p;
|
++p;
|
||||||
p = XMLBase::ParseText( p, &value, endTag, StrPair::ATTRIBUTE_VALUE );
|
p = value.ParseText( p, endTag, StrPair::ATTRIBUTE_VALUE );
|
||||||
if ( value.Empty() ) return 0;
|
if ( value.Empty() ) return 0;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -452,14 +499,14 @@ char* XMLElement::ParseAttributes( char* p, bool* closedElement )
|
||||||
|
|
||||||
// Read the attributes.
|
// Read the attributes.
|
||||||
while( p ) {
|
while( p ) {
|
||||||
p = XMLBase::SkipWhiteSpace( p );
|
p = XMLUtil::SkipWhiteSpace( p );
|
||||||
if ( !p || !(*p) ) {
|
if ( !p || !(*p) ) {
|
||||||
document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, Name() );
|
document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, Name() );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// attribute.
|
// attribute.
|
||||||
if ( XMLBase::IsAlpha( *p ) ) {
|
if ( XMLUtil::IsAlpha( *p ) ) {
|
||||||
XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute( this );
|
XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute( this );
|
||||||
attrib->memPool = &document->attributePool;
|
attrib->memPool = &document->attributePool;
|
||||||
|
|
||||||
|
@ -508,7 +555,7 @@ char* XMLElement::ParseAttributes( char* p, bool* closedElement )
|
||||||
char* XMLElement::ParseDeep( char* p )
|
char* XMLElement::ParseDeep( char* p )
|
||||||
{
|
{
|
||||||
// Read the element name.
|
// Read the element name.
|
||||||
p = XMLBase::SkipWhiteSpace( p );
|
p = XMLUtil::SkipWhiteSpace( p );
|
||||||
if ( !p ) return 0;
|
if ( !p ) return 0;
|
||||||
const char* start = p;
|
const char* start = p;
|
||||||
|
|
||||||
|
@ -520,7 +567,7 @@ char* XMLElement::ParseDeep( char* p )
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = XMLBase::ParseName( p, &value );
|
p = value.ParseName( p );
|
||||||
if ( value.Empty() ) return 0;
|
if ( value.Empty() ) return 0;
|
||||||
|
|
||||||
bool elementClosed=false;
|
bool elementClosed=false;
|
||||||
|
@ -539,7 +586,7 @@ void XMLElement::Print( XMLStreamer* streamer )
|
||||||
// PrintSpace( cfile, depth );
|
// PrintSpace( cfile, depth );
|
||||||
//}
|
//}
|
||||||
//fprintf( cfile, "<%s", Name() );
|
//fprintf( cfile, "<%s", Name() );
|
||||||
streamer->OpenElement( Name(), IsTextParent() );
|
streamer->OpenElement( Name() );
|
||||||
|
|
||||||
for( XMLAttribute* attrib=rootAttribute; attrib; attrib=attrib->next ) {
|
for( XMLAttribute* attrib=rootAttribute; attrib; attrib=attrib->next ) {
|
||||||
//fprintf( cfile, " " );
|
//fprintf( cfile, " " );
|
||||||
|
@ -554,6 +601,21 @@ void XMLElement::Print( XMLStreamer* streamer )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool XMLElement::Accept( XMLVisitor* visitor ) const
|
||||||
|
{
|
||||||
|
if ( visitor->VisitEnter( *this, rootAttribute ) )
|
||||||
|
{
|
||||||
|
for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
|
||||||
|
{
|
||||||
|
if ( !node->Accept( visitor ) )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return visitor->VisitExit( *this );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// --------- XMLDocument ----------- //
|
// --------- XMLDocument ----------- //
|
||||||
XMLDocument::XMLDocument() :
|
XMLDocument::XMLDocument() :
|
||||||
XMLNode( 0 ),
|
XMLNode( 0 ),
|
||||||
|
@ -678,7 +740,7 @@ const char* StringStack::Pop() {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
XMLStreamer::XMLStreamer( FILE* file ) : fp( file ), depth( 0 ), elementJustOpened( false )
|
XMLStreamer::XMLStreamer( FILE* file ) : fp( file ), depth( 0 ), elementJustOpened( false ), textDepth( -1 )
|
||||||
{
|
{
|
||||||
for( int i=0; i<ENTITY_RANGE; ++i ) {
|
for( int i=0; i<ENTITY_RANGE; ++i ) {
|
||||||
entityFlag[i] = false;
|
entityFlag[i] = false;
|
||||||
|
@ -733,18 +795,18 @@ void XMLStreamer::PrintString( const char* p )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XMLStreamer::OpenElement( const char* name, bool textParent )
|
void XMLStreamer::OpenElement( const char* name )
|
||||||
{
|
{
|
||||||
if ( elementJustOpened ) {
|
if ( elementJustOpened ) {
|
||||||
SealElement();
|
SealElement();
|
||||||
}
|
}
|
||||||
if ( !TextOnStack() ) {
|
stack.Push( name );
|
||||||
|
|
||||||
|
if ( textDepth < 0 && depth > 0) {
|
||||||
|
fprintf( fp, "\n" );
|
||||||
PrintSpace( depth );
|
PrintSpace( depth );
|
||||||
}
|
}
|
||||||
stack.Push( name );
|
|
||||||
text.Push( textParent ? 'T' : 'e' );
|
|
||||||
|
|
||||||
// fixme: can names have entities?
|
|
||||||
fprintf( fp, "<%s", name );
|
fprintf( fp, "<%s", name );
|
||||||
elementJustOpened = true;
|
elementJustOpened = true;
|
||||||
++depth;
|
++depth;
|
||||||
|
@ -764,25 +826,22 @@ void XMLStreamer::CloseElement()
|
||||||
{
|
{
|
||||||
--depth;
|
--depth;
|
||||||
const char* name = stack.Pop();
|
const char* name = stack.Pop();
|
||||||
bool wasText = TextOnStack();
|
|
||||||
text.Pop();
|
|
||||||
|
|
||||||
if ( elementJustOpened ) {
|
if ( elementJustOpened ) {
|
||||||
fprintf( fp, "/>" );
|
fprintf( fp, "/>" );
|
||||||
if ( !wasText ) {
|
|
||||||
fprintf( fp, "\n" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( !wasText ) {
|
if ( textDepth < 0 ) {
|
||||||
|
fprintf( fp, "\n" );
|
||||||
PrintSpace( depth );
|
PrintSpace( depth );
|
||||||
}
|
}
|
||||||
// fixme can names have entities?
|
|
||||||
fprintf( fp, "</%s>", name );
|
fprintf( fp, "</%s>", name );
|
||||||
if ( !TextOnStack() ) {
|
|
||||||
fprintf( fp, "\n" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( textDepth == depth )
|
||||||
|
textDepth = -1;
|
||||||
|
if ( depth == 0 )
|
||||||
|
fprintf( fp, "\n" );
|
||||||
elementJustOpened = false;
|
elementJustOpened = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -791,14 +850,13 @@ void XMLStreamer::SealElement()
|
||||||
{
|
{
|
||||||
elementJustOpened = false;
|
elementJustOpened = false;
|
||||||
fprintf( fp, ">" );
|
fprintf( fp, ">" );
|
||||||
if ( !TextOnStack() ) {
|
|
||||||
fprintf( fp, "\n" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void XMLStreamer::PushText( const char* text )
|
void XMLStreamer::PushText( const char* text )
|
||||||
{
|
{
|
||||||
|
textDepth = depth-1;
|
||||||
|
|
||||||
if ( elementJustOpened ) {
|
if ( elementJustOpened ) {
|
||||||
SealElement();
|
SealElement();
|
||||||
}
|
}
|
||||||
|
|
138
tinyxml2.h
138
tinyxml2.h
|
@ -12,7 +12,7 @@
|
||||||
- make constructors protected
|
- make constructors protected
|
||||||
- hide copy constructor
|
- hide copy constructor
|
||||||
- hide = operator
|
- hide = operator
|
||||||
- UTF8 support: isAlpha, etc.
|
X UTF8 support: isAlpha, etc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
@ -74,6 +74,9 @@ public:
|
||||||
bool Empty() const { return start == end; }
|
bool Empty() const { return start == end; }
|
||||||
|
|
||||||
void SetInternedStr( const char* str ) { this->start = (char*) str; this->end = 0; this->flags = 0; }
|
void SetInternedStr( const char* str ) { this->start = (char*) str; this->end = 0; this->flags = 0; }
|
||||||
|
char* ParseText( char* in, const char* endTag, int strFlags );
|
||||||
|
char* ParseName( char* in );
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum {
|
enum {
|
||||||
|
@ -278,16 +281,59 @@ private:
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class XMLBase
|
|
||||||
|
/**
|
||||||
|
Implements the interface to the "Visitor pattern" (see the Accept() method.)
|
||||||
|
If you call the Accept() method, it requires being passed a XMLVisitor
|
||||||
|
class to handle callbacks. For nodes that contain other nodes (Document, Element)
|
||||||
|
you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves
|
||||||
|
are simply called with Visit().
|
||||||
|
|
||||||
|
If you return 'true' from a Visit method, recursive parsing will continue. If you return
|
||||||
|
false, <b>no children of this node or its sibilings</b> will be Visited.
|
||||||
|
|
||||||
|
All flavors of Visit methods have a default implementation that returns 'true' (continue
|
||||||
|
visiting). You need to only override methods that are interesting to you.
|
||||||
|
|
||||||
|
Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.
|
||||||
|
|
||||||
|
You should never change the document from a callback.
|
||||||
|
|
||||||
|
@sa XMLNode::Accept()
|
||||||
|
*/
|
||||||
|
class XMLVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
virtual ~XMLVisitor() {}
|
||||||
|
|
||||||
|
/// Visit a document.
|
||||||
|
virtual bool VisitEnter( const XMLDocument& /*doc*/ ) { return true; }
|
||||||
|
/// Visit a document.
|
||||||
|
virtual bool VisitExit( const XMLDocument& /*doc*/ ) { return true; }
|
||||||
|
|
||||||
|
/// Visit an element.
|
||||||
|
virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ ) { return true; }
|
||||||
|
/// Visit an element.
|
||||||
|
virtual bool VisitExit( const XMLElement& /*element*/ ) { return true; }
|
||||||
|
|
||||||
|
/// Visit a declaration
|
||||||
|
//virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; }
|
||||||
|
/// Visit a text node
|
||||||
|
virtual bool Visit( const XMLText& /*text*/ ) { return true; }
|
||||||
|
/// Visit a comment node
|
||||||
|
virtual bool Visit( const XMLComment& /*comment*/ ) { return true; }
|
||||||
|
/// Visit an unknown node
|
||||||
|
//virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class XMLUtil
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
XMLBase() {}
|
// Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
|
||||||
virtual ~XMLBase() {}
|
// correct, but simple, and usually works.
|
||||||
|
static const char* SkipWhiteSpace( const char* p ) { while( IsUTF8Continuation(*p) || isspace( *p ) ) { ++p; } return p; }
|
||||||
static const char* SkipWhiteSpace( const char* p ) { while( isspace( *p ) ) { ++p; } return p; }
|
static char* SkipWhiteSpace( char* p ) { while( IsUTF8Continuation(*p) || isspace( *p ) ) { ++p; } return p; }
|
||||||
static char* SkipWhiteSpace( char* p ) { while( isspace( *p ) ) { ++p; } return p; }
|
|
||||||
|
|
||||||
inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
|
inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
@ -303,13 +349,8 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
inline static int IsUTF8Continuation( unsigned char p ) { return p & 0x80; }
|
inline static int IsUTF8Continuation( unsigned char p ) { return p & 0x80; }
|
||||||
inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte <= 127 ) ? isalnum( anyByte ) : 1; }
|
inline static int IsAlphaNum( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalnum( anyByte ) : 1; }
|
||||||
inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte <= 127 ) ? isalpha( anyByte ) : 1; }
|
inline static int IsAlpha( unsigned char anyByte ) { return ( anyByte < 128 ) ? isalpha( anyByte ) : 1; }
|
||||||
|
|
||||||
static char* ParseText( char* in, StrPair* pair, const char* endTag, int strFlags );
|
|
||||||
static char* ParseName( char* in, StrPair* pair );
|
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -318,25 +359,50 @@ class XMLNode
|
||||||
friend class XMLDocument;
|
friend class XMLDocument;
|
||||||
friend class XMLElement;
|
friend class XMLElement;
|
||||||
public:
|
public:
|
||||||
//void* operator new( size_t size, MemPool* pool );
|
XMLDocument* GetDocument() { return document; }
|
||||||
//void operator delete( void* mem, MemPool* pool );
|
|
||||||
|
|
||||||
XMLNode* InsertEndChild( XMLNode* addThis );
|
virtual XMLElement* ToElement() { return 0; }
|
||||||
virtual void Print( XMLStreamer* streamer );
|
virtual XMLText* ToText() { return 0; }
|
||||||
|
virtual XMLComment* ToComment() { return 0; }
|
||||||
|
virtual XMLDocument* ToDocument() { return 0; }
|
||||||
|
|
||||||
const char* Value() const { return value.GetStr(); }
|
const char* Value() const { return value.GetStr(); }
|
||||||
void SetValue( const char* val ) { value.SetInternedStr( val ); }
|
void SetValue( const char* val ) { value.SetInternedStr( val ); }
|
||||||
|
|
||||||
virtual XMLElement* ToElement() { return 0; }
|
const XMLNode* FirstChild() const { return firstChild; }
|
||||||
virtual XMLText* ToText() { return 0; }
|
XMLNode* FirstChild() { return firstChild; }
|
||||||
virtual XMLComment* ToComment() { return 0; }
|
const XMLElement* FirstChildElement( const char* value=0 ) const;
|
||||||
|
XMLElement* FirstChildElement( const char* value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( value )); }
|
||||||
|
|
||||||
XMLNode* FirstChild() { return firstChild; }
|
const XMLNode* LastChild() const { return lastChild; }
|
||||||
XMLElement* FirstChildElement( const char* value=0 );
|
XMLNode* LastChild() { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->LastChild() ); }
|
||||||
|
|
||||||
|
const XMLElement* LastChildElement( const char* value=0 ) const;
|
||||||
|
XMLElement* LastChildElement( const char* value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(value) ); }
|
||||||
|
|
||||||
|
const XMLNode* PreviousSibling() const { return prev; }
|
||||||
|
XMLNode* PreviousSibling() { return prev; }
|
||||||
|
|
||||||
|
const XMLNode* PreviousSiblingElement( const char* value=0 ) const ;
|
||||||
|
XMLNode* PreviousSiblingElement( const char* value=0 ) { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( value ) ); }
|
||||||
|
|
||||||
|
const XMLNode* NextSibling() const { return next; }
|
||||||
|
XMLNode* NextSibling() { return next; }
|
||||||
|
|
||||||
|
const XMLNode* NextSiblingElement( const char* value=0 ) const;
|
||||||
|
XMLNode* NextSiblingElement( const char* value=0 ) { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->NextSiblingElement( value ) ); }
|
||||||
|
|
||||||
|
XMLNode* InsertEndChild( XMLNode* addThis );
|
||||||
|
XMLNode* InsertFirstChild( XMLNode* addThis );
|
||||||
|
XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
|
||||||
|
|
||||||
|
void ClearChildren();
|
||||||
|
void DeleteChild( XMLNode* node );
|
||||||
|
|
||||||
|
virtual bool Accept( XMLVisitor* visitor ) const = 0;
|
||||||
|
virtual void Print( XMLStreamer* streamer );
|
||||||
|
|
||||||
// fixme: guarentee null terminator to avoid internal checks
|
|
||||||
virtual char* ParseDeep( char* );
|
virtual char* ParseDeep( char* );
|
||||||
|
|
||||||
void SetTextParent() { isTextParent = true; }
|
void SetTextParent() { isTextParent = true; }
|
||||||
bool IsTextParent() const { return isTextParent; }
|
bool IsTextParent() const { return isTextParent; }
|
||||||
virtual bool IsClosingElement() const { return false; }
|
virtual bool IsClosingElement() const { return false; }
|
||||||
|
@ -345,8 +411,6 @@ protected:
|
||||||
XMLNode( XMLDocument* );
|
XMLNode( XMLDocument* );
|
||||||
virtual ~XMLNode();
|
virtual ~XMLNode();
|
||||||
|
|
||||||
void ClearChildren();
|
|
||||||
|
|
||||||
XMLDocument* document;
|
XMLDocument* document;
|
||||||
XMLNode* parent;
|
XMLNode* parent;
|
||||||
bool isTextParent;
|
bool isTextParent;
|
||||||
|
@ -373,6 +437,7 @@ public:
|
||||||
const char* Value() { return value.GetStr(); }
|
const char* Value() { return value.GetStr(); }
|
||||||
void SetValue( const char* );
|
void SetValue( const char* );
|
||||||
|
|
||||||
|
virtual bool Accept( XMLVisitor* visitor ) const;
|
||||||
virtual XMLText* ToText() { return this; }
|
virtual XMLText* ToText() { return this; }
|
||||||
|
|
||||||
char* ParseDeep( char* );
|
char* ParseDeep( char* );
|
||||||
|
@ -394,6 +459,7 @@ public:
|
||||||
virtual XMLComment* ToComment() { return this; }
|
virtual XMLComment* ToComment() { return this; }
|
||||||
|
|
||||||
const char* Value() { return value.GetStr(); }
|
const char* Value() { return value.GetStr(); }
|
||||||
|
virtual bool Accept( XMLVisitor* visitor ) const;
|
||||||
|
|
||||||
char* ParseDeep( char* );
|
char* ParseDeep( char* );
|
||||||
|
|
||||||
|
@ -405,7 +471,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class XMLAttribute : public XMLBase
|
class XMLAttribute
|
||||||
{
|
{
|
||||||
friend class XMLElement;
|
friend class XMLElement;
|
||||||
public:
|
public:
|
||||||
|
@ -434,6 +500,7 @@ public:
|
||||||
virtual void Print( XMLStreamer* );
|
virtual void Print( XMLStreamer* );
|
||||||
|
|
||||||
virtual XMLElement* ToElement() { return this; }
|
virtual XMLElement* ToElement() { return this; }
|
||||||
|
virtual bool Accept( XMLVisitor* visitor ) const;
|
||||||
|
|
||||||
// internal:
|
// internal:
|
||||||
virtual bool IsClosingElement() const { return closing; }
|
virtual bool IsClosingElement() const { return closing; }
|
||||||
|
@ -459,11 +526,14 @@ public:
|
||||||
XMLDocument();
|
XMLDocument();
|
||||||
~XMLDocument();
|
~XMLDocument();
|
||||||
|
|
||||||
|
virtual XMLDocument* ToDocument() { return this; }
|
||||||
|
|
||||||
int Parse( const char* );
|
int Parse( const char* );
|
||||||
int Load( const char* );
|
int Load( const char* );
|
||||||
int Load( FILE* );
|
int Load( FILE* );
|
||||||
|
|
||||||
void Print( XMLStreamer* streamer=0 );
|
void Print( XMLStreamer* streamer=0 );
|
||||||
|
virtual bool Accept( XMLVisitor* visitor ) const;
|
||||||
|
|
||||||
XMLElement* NewElement( const char* name );
|
XMLElement* NewElement( const char* name );
|
||||||
|
|
||||||
|
@ -500,13 +570,13 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class XMLStreamer
|
class XMLStreamer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
XMLStreamer( FILE* file );
|
XMLStreamer( FILE* file );
|
||||||
~XMLStreamer() {}
|
~XMLStreamer() {}
|
||||||
|
|
||||||
void OpenElement( const char* name, bool textParent );
|
void OpenElement( const char* name );
|
||||||
void PushAttribute( const char* name, const char* value );
|
void PushAttribute( const char* name, const char* value );
|
||||||
void CloseElement();
|
void CloseElement();
|
||||||
|
|
||||||
|
@ -517,24 +587,26 @@ private:
|
||||||
void SealElement();
|
void SealElement();
|
||||||
void PrintSpace( int depth );
|
void PrintSpace( int depth );
|
||||||
void PrintString( const char* ); // prints out, after detecting entities.
|
void PrintString( const char* ); // prints out, after detecting entities.
|
||||||
bool TextOnStack() const {
|
/* bool TextOnStack() const {
|
||||||
for( int i=0; i<text.Size(); ++i ) {
|
for( int i=0; i<text.Size(); ++i ) {
|
||||||
if ( text[i] == 'T' )
|
if ( text[i] == 'T' )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
FILE* fp;
|
FILE* fp;
|
||||||
int depth;
|
int depth;
|
||||||
bool elementJustOpened;
|
bool elementJustOpened;
|
||||||
|
int textDepth;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
ENTITY_RANGE = 64
|
ENTITY_RANGE = 64
|
||||||
};
|
};
|
||||||
bool entityFlag[ENTITY_RANGE];
|
bool entityFlag[ENTITY_RANGE];
|
||||||
|
|
||||||
DynArray< const char*, 10 > stack;
|
DynArray< const char*, 10 > stack;
|
||||||
DynArray< char, 10 > text;
|
//DynArray< char, 10 > text;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ int main( int argc, const char* argv )
|
||||||
printf( "----------------------------------------------\n" );
|
printf( "----------------------------------------------\n" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
{
|
{
|
||||||
static const char* test = "<element>Text before.</element>";
|
static const char* test = "<element>Text before.</element>";
|
||||||
XMLDocument doc;
|
XMLDocument doc;
|
||||||
|
@ -67,5 +68,6 @@ int main( int argc, const char* argv )
|
||||||
doc->Parse( test );
|
doc->Parse( test );
|
||||||
delete doc;
|
delete doc;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
Loading…
Reference in New Issue