Mbed port of the Simple Plain Xml parser. See http://code.google.com/p/spxml/ for more details. This library uses less memory and is much better suited to streaming data than TinyXML (doesn\'t use as much C++ features, and especially works without streams). See http://mbed.org/users/hlipka/notebook/xml-parsing/ for usage examples.

Dependents:   spxmltest_weather VFD_fontx2_weather weather_LCD_display News_LCD_display ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers spdomparser.cpp Source File

spdomparser.cpp

00001 /*
00002  * Copyright 2007 Stephen Liu
00003  * LGPL, see http://code.google.com/p/spxml/
00004  * For license terms, see the file COPYING along with this library.
00005  */
00006 
00007 #include <assert.h>
00008 
00009 #include "spdomparser.hpp"
00010 #include "spxmlparser.hpp"
00011 #include "spxmlevent.hpp"
00012 #include "spxmlutils.hpp"
00013 #include "spxmlnode.hpp"
00014 #include "spxmlcodec.hpp"
00015 
00016 //=========================================================
00017 
00018 SP_XmlDomParser :: SP_XmlDomParser()
00019 {
00020     mParser = new SP_XmlPullParser();
00021     mDocument = new SP_XmlDocument();
00022     mCurrent = NULL;
00023 }
00024 
00025 SP_XmlDomParser :: ~SP_XmlDomParser()
00026 {
00027     if( NULL != mDocument ) delete mDocument;
00028     mDocument = NULL;
00029 
00030     if( NULL != mParser ) delete mParser;
00031     mParser = NULL;
00032 }
00033 
00034 void SP_XmlDomParser :: setIgnoreWhitespace( int ignoreWhitespace )
00035 {
00036     mParser->setIgnoreWhitespace( ignoreWhitespace );
00037 }
00038 
00039 int SP_XmlDomParser :: getIgnoreWhitespace()
00040 {
00041     return mParser->getIgnoreWhitespace();
00042 }
00043 
00044 const char * SP_XmlDomParser :: getEncoding()
00045 {
00046     return mParser->getEncoding();
00047 }
00048 
00049 int SP_XmlDomParser :: append( const char * source, int len )
00050 {
00051     int ret = 0;
00052 
00053     for( int pos = 0; pos < len; pos += 64 ) {
00054         int realLen = ( len - pos ) > 64 ? 64 : ( len - pos );
00055         ret += mParser->append( source + pos, realLen );
00056         buildTree();
00057     }
00058 
00059     return ret;
00060 }
00061 
00062 void SP_XmlDomParser :: buildTree()
00063 {
00064     for( SP_XmlPullEvent * event = mParser->getNext();
00065             NULL != event; event = mParser->getNext() ) {
00066 
00067         switch( event->getEventType() ) {
00068             case SP_XmlPullEvent::eStartDocument:
00069                 // ignore
00070                 delete event;
00071                 break;
00072             case SP_XmlPullEvent::eEndDocument:
00073                 // ignore
00074                 delete event;
00075                 break;
00076             case SP_XmlPullEvent::eDocDecl:
00077                 {
00078                     mDocument->setDocDecl(
00079                             new SP_XmlDocDeclNode( (SP_XmlDocDeclEvent*)event ) );
00080                     break;
00081                 }
00082             case SP_XmlPullEvent::eDocType:
00083                 {
00084                     mDocument->setDocType(
00085                             new SP_XmlDocTypeNode( (SP_XmlDocTypeEvent*)event ) );
00086                     break;
00087                 }
00088             case SP_XmlPullEvent::eStartTag:
00089                 {
00090                     SP_XmlElementNode * element =
00091                             new SP_XmlElementNode( (SP_XmlStartTagEvent*)event );
00092                     if( NULL == mCurrent ) {
00093                         mCurrent = element;
00094                         mDocument->setRootElement( element );
00095                     } else {
00096                         mCurrent->addChild( element );
00097                         mCurrent = element;
00098                     }
00099                     break;
00100                 }
00101             case SP_XmlPullEvent::eEndTag:
00102                 {
00103                     SP_XmlNode * parent = (SP_XmlNode*)mCurrent->getParent();
00104                     if( NULL != parent && SP_XmlNode::eELEMENT == parent->getType() ) {
00105                         mCurrent = static_cast<SP_XmlElementNode*>((SP_XmlNode*)parent);
00106                     } else {
00107                         mCurrent = NULL;
00108                     }
00109 
00110                     delete event;
00111                     break;
00112                 }
00113             case SP_XmlPullEvent::eCData:
00114                 {
00115                     if( NULL != mCurrent ) {
00116                         mCurrent->addChild( new SP_XmlCDataNode( (SP_XmlCDataEvent*)event ) );
00117                     } else {
00118                         delete event;
00119                     }
00120                     break;
00121                 }
00122             case SP_XmlPullEvent::eComment:
00123                 {
00124                     if( NULL != mCurrent ) {
00125                         mCurrent->addChild( new SP_XmlCommentNode( (SP_XmlCommentEvent*)event ) );
00126                     } else {
00127                         delete event;
00128                     }
00129                     break;
00130                 }
00131             case SP_XmlPIEvent::ePI:
00132                 {
00133                     if( NULL != mCurrent ) {
00134                         mCurrent->addChild( new SP_XmlPINode( (SP_XmlPIEvent*)event ) );
00135                     } else {
00136                         mDocument->getChildren()->append(
00137                                 new SP_XmlPINode( (SP_XmlPIEvent*)event ) );
00138                     }
00139                     break;
00140                 }
00141             default:
00142                 {
00143                     assert( 0 );
00144                     break;
00145                 }
00146         }
00147     }
00148 }
00149 
00150 const char * SP_XmlDomParser :: getError ()
00151 {
00152     return mParser->getError();
00153 }
00154 
00155 const SP_XmlDocument * SP_XmlDomParser :: getDocument() const
00156 {
00157     return mDocument;
00158 }
00159 
00160 //=========================================================
00161 
00162 SP_XmlDomBuffer :: SP_XmlDomBuffer( const SP_XmlNode * node, int indent )
00163 {
00164     mBuffer = new SP_XmlStringBuffer();
00165     dump( SP_XmlStringCodec::DEFAULT_ENCODING, node, mBuffer, indent ? 0 : -1 );
00166 }
00167 
00168 SP_XmlDomBuffer :: SP_XmlDomBuffer( const char * encoding, const SP_XmlNode * node, int indent )
00169 {
00170     mBuffer = new SP_XmlStringBuffer();
00171     dump( encoding, node, mBuffer, indent ? 0 : -1 );
00172 }
00173 
00174 SP_XmlDomBuffer :: ~SP_XmlDomBuffer()
00175 {
00176     if( NULL != mBuffer ) delete mBuffer;
00177     mBuffer = NULL;
00178 }
00179 
00180 const char * SP_XmlDomBuffer :: getBuffer() const
00181 {
00182     return mBuffer->getBuffer();
00183 }
00184 
00185 int SP_XmlDomBuffer :: getSize() const
00186 {
00187     return mBuffer->getSize();
00188 }
00189 
00190 void SP_XmlDomBuffer :: dump( const char * encoding,
00191         const SP_XmlNode * node, SP_XmlStringBuffer * buffer, int level )
00192 {
00193     if( SP_XmlNode::eXMLDOC == node->getType() ) {
00194         SP_XmlDocument * document = static_cast<SP_XmlDocument*>((SP_XmlNode*)node);
00195         dumpDocDecl( encoding, document->getDocDecl(), buffer, level );
00196         dumpDocType( encoding, document->getDocType(), buffer, level );
00197 
00198         const SP_XmlNodeList * children = document->getChildren();
00199         for( int j = 0; j < children->getLength(); j++ ) {
00200             dump( encoding, children->get( j ), buffer, level );
00201         }
00202     } else if( SP_XmlNode::eCDATA == node->getType() ) {
00203         SP_XmlCDataNode * cdata = static_cast<SP_XmlCDataNode*>((SP_XmlNode*)node);
00204         SP_XmlStringCodec::encode( encoding, cdata->getText(), buffer );
00205     } else if( SP_XmlNode::eCOMMENT == node->getType() ) {
00206         SP_XmlCommentNode * comment = static_cast<SP_XmlCommentNode*>((SP_XmlNode*)node);
00207 
00208         if( level >= 0 ) {
00209             buffer->append( '\n' );
00210             for( int i = 0; i < level; i++ ) buffer->append( '\t' );
00211             buffer->append( "<!--" );
00212             buffer->append( comment->getText() );
00213             buffer->append( "-->\n" );
00214         } else {
00215             buffer->append( "<!--" );
00216             buffer->append( comment->getText() );
00217             buffer->append( "-->" );
00218         }
00219     } else if( SP_XmlNode::eELEMENT == node->getType() ) {
00220         dumpElement( encoding, node, buffer, level );
00221     } else if( SP_XmlNode::eDOCDECL == node->getType() ) {
00222         dumpDocDecl( encoding, (SP_XmlDocDeclNode*)node, buffer, level );
00223     } else if( SP_XmlNode::eDOCTYPE == node->getType() ) {
00224         dumpDocType( encoding, (SP_XmlDocTypeNode*)node, buffer, level );
00225     } else if( SP_XmlNode::ePI == node->getType() ) {
00226         SP_XmlPINode * piNode = static_cast<SP_XmlPINode*>((SP_XmlNode*)node);
00227 
00228         if( level >= 0 ) {
00229             for( int i = 0; i < level; i++ ) buffer->append( '\t' );
00230             buffer->append( "<?" );
00231             buffer->append( piNode->getTarget() );
00232             buffer->append( ' ' );
00233             buffer->append( piNode->getData() );
00234             buffer->append( "?>\n" );
00235         } else {
00236             buffer->append( "<?" );
00237             buffer->append( piNode->getTarget() );
00238             if( '\0' != *( piNode->getTarget() ) ) buffer->append( ' ' );
00239             buffer->append( piNode->getData() );
00240             buffer->append( "?>" );
00241         }
00242     } else {
00243         // ignore
00244     }
00245 }
00246 
00247 void SP_XmlDomBuffer :: dumpDocDecl( const char * encoding,
00248         const SP_XmlDocDeclNode * docDecl,
00249         SP_XmlStringBuffer * buffer, int level )
00250 {
00251     if( NULL == docDecl ) return;
00252 
00253     buffer->append( "<?xml version=\"" );
00254     if( '\0' != * ( docDecl->getVersion() ) ) {
00255         buffer->append( docDecl->getVersion() );
00256     } else {
00257         buffer->append( "1.0" );
00258     }
00259     buffer->append( "\" " );
00260 
00261     if( '\0' != * ( docDecl->getEncoding() ) ) {
00262         buffer->append( "encoding=\"" );
00263         buffer->append( docDecl->getEncoding() );
00264         buffer->append( "\" " );
00265     }
00266 
00267     if( -1 != docDecl->getStandalone() ) {
00268         char standalone[ 32 ];
00269         snprintf( standalone, sizeof( standalone ), "standalone=\"%s\" ",
00270                 0 == docDecl->getStandalone() ? "no" : "yes" );
00271         buffer->append( standalone );
00272     }
00273 
00274     buffer->append( level >= 0 ? "?>\n" : "?>" );
00275 }
00276 
00277 void SP_XmlDomBuffer :: dumpDocType( const char * encoding,
00278         const SP_XmlDocTypeNode * docType,
00279         SP_XmlStringBuffer * buffer, int level )
00280 {
00281     if( NULL == docType ) return;
00282 
00283     buffer->append( "<!DOCTYPE " );
00284     buffer->append( docType->getName() );
00285 
00286     if( '\0' != * ( docType->getPublicID() ) ) {
00287         buffer->append( " PUBLIC " );
00288         buffer->append( '"' );
00289         buffer->append( docType->getPublicID() );
00290         buffer->append( '"' );
00291     }
00292 
00293     if( '\0' != * ( docType->getSystemID() ) ) {
00294         buffer->append( " SYSTEM " );
00295         buffer->append( '"' );
00296         buffer->append( docType->getSystemID() );
00297         buffer->append( '"' );
00298     }
00299 
00300     if( '\0' != * ( docType->getDTD() ) ) {
00301         buffer->append( " \"" );
00302         buffer->append( docType->getDTD() );
00303         buffer->append( '"' );
00304     }
00305 
00306     buffer->append( level >= 0 ? ">\n" : ">" );
00307 }
00308 
00309 void SP_XmlDomBuffer :: dumpElement( const char * encoding,
00310         const SP_XmlNode * node, SP_XmlStringBuffer * buffer, int level )
00311 {
00312     if( NULL == node ) return;
00313 
00314     if( SP_XmlNode::eELEMENT == node->getType() ) {
00315         int i = 0;
00316 
00317         for( i = 0; i < level; i++ ) buffer->append( '\t' );
00318 
00319         SP_XmlElementNode * element = static_cast<SP_XmlElementNode*>((SP_XmlNode*)node);
00320         buffer->append( "<" );
00321         buffer->append( element->getName() );
00322 
00323         const char * name = NULL, * value = NULL;
00324         for( i = 0; i < element->getAttrCount(); i++ ) {
00325             name = element->getAttr( i, &value );
00326             if( NULL != name && NULL != value ) {
00327                 buffer->append( ' ' );
00328                 buffer->append( name );
00329                 buffer->append( "=\"" );
00330                 SP_XmlStringCodec::encode( encoding, value, buffer );
00331                 buffer->append( "\"" );
00332             }
00333         }
00334 
00335         const SP_XmlNodeList * children = element->getChildren();
00336 
00337         if( children->getLength() > 0 ) {
00338             if( SP_XmlNode::eCDATA != children->get( 0 )->getType() ) {
00339                 buffer->append( level >= 0 ? ">\n" : ">" );
00340             } else {
00341                 buffer->append( ">" );
00342             }
00343 
00344             for( int j = 0; j < children->getLength(); j++ ) {
00345                 dump( encoding, children->get( j ), buffer, level >= 0 ? level + 1 : -1 );
00346             }
00347 
00348             if( SP_XmlNode::eCDATA != children->get( 0 )->getType() ) {
00349                 for( int i = 0; i < level; i++ ) buffer->append( '\t' );
00350             }
00351             buffer->append( "</" );
00352             buffer->append( element->getName() );
00353             buffer->append( level >= 0 ? ">\n" : ">" );
00354         } else {
00355             buffer->append( level >= 0 ? "/>\n" : ">" );
00356         }
00357     } else {
00358         dump( encoding, node, buffer, level );
00359     }
00360 }
00361