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
Diff: spxmlparser.cpp
- Revision:
- 0:3fa97f2c0505
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spxmlparser.cpp Wed Nov 24 20:52:14 2010 +0000 @@ -0,0 +1,222 @@ +/* + * Copyright 2007 Stephen Liu + * LGPL, see http://code.google.com/p/spxml/ + * For license terms, see the file COPYING along with this library. + */ + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <typeinfo> + +#include "mstring.h" + +#include "spxmlparser.hpp" +#include "spxmlreader.hpp" +#include "spxmlutils.hpp" +#include "spxmlevent.hpp" +#include "spxmlcodec.hpp" + +SP_XmlPullParser :: SP_XmlPullParser() +{ + mReaderPool = new SP_XmlReaderPool(); + mReader = getReader( SP_XmlReader::eLBracket ); + mEventQueue = new SP_XmlPullEventQueue(); + mEventQueue->enqueue( new SP_XmlStartDocEvent() ); + + mRootTagState = eRootNone; + mTagNameStack = new SP_XmlArrayList(); + mLevel = 0; + + mIgnoreWhitespace = 1; + + mError = NULL; + + memset( mErrorSegment, 0, sizeof( mErrorSegment ) ); + mErrorIndex = 0; + mRowIndex = mColIndex = 0; + + memset( mEncoding, 0, sizeof( mEncoding ) ); +} + +SP_XmlPullParser :: ~SP_XmlPullParser() +{ + mReaderPool->save( mReader ); + + for( int i = 0; i < mTagNameStack->getCount(); i++ ) { + free( (char*)mTagNameStack->getItem( i ) ); + } + delete mTagNameStack; + + delete mEventQueue; + + delete mReaderPool; + + if( NULL != mError ) free( mError ); +} + +const char * SP_XmlPullParser :: getEncoding() +{ + if( '\0' == mEncoding[0] ) { + return SP_XmlStringCodec::DEFAULT_ENCODING; + } + + return mEncoding; +} + +int SP_XmlPullParser :: append( const char * source, int len ) +{ + if( NULL != mError ) return 0; + + int consumed = 0; + + for( int i = 0; i < len && NULL == mError; i++ ) { + + consumed++; + + char c = source[ i ]; + + mErrorSegment[ mErrorIndex++ % sizeof( mErrorSegment ) ] = c; + mReader->read( this, c ); + if( '\n' == c ) { + mRowIndex++; + mColIndex = 0; + } else { + mColIndex++; + } + } + + return consumed; +} + +SP_XmlPullEvent * SP_XmlPullParser :: getNext() +{ + SP_XmlPullEvent * event = mEventQueue->dequeue(); + + if( NULL != event ) { + if( SP_XmlPullEvent::eStartTag == event->getEventType() ) mLevel++; + if( SP_XmlPullEvent::eEndTag == event->getEventType() ) mLevel--; + } + + return event; +} + +int SP_XmlPullParser :: getLevel() +{ + return mLevel; +} + +void SP_XmlPullParser :: setIgnoreWhitespace( int ignoreWhitespace ) +{ + mIgnoreWhitespace = ignoreWhitespace; +} + +int SP_XmlPullParser :: getIgnoreWhitespace() +{ + return mIgnoreWhitespace; +} + +const char * SP_XmlPullParser :: getError() +{ + return mError; +} + +void SP_XmlPullParser :: changeReader( SP_XmlReader * reader ) +{ + SP_XmlPullEvent * event = mReader->getEvent( this ); + if( NULL != event ) { + if( SP_XmlPullEvent::eStartTag == event->getEventType() ) { + if( eRootNone == mRootTagState ) mRootTagState = eRootStart; + const char * name = ((SP_XmlStartTagEvent*)event)->getName(); + mTagNameStack->append( strdup( name ) ); + } + if( SP_XmlPullEvent::eEndTag == event->getEventType() ) { + char error[ 256 ] = { 0 }; + + const char * etag = ((SP_XmlEndTagEvent*)event)->getText(); + char * stag = (char*)mTagNameStack->takeItem( SP_XmlArrayList::LAST_INDEX ); + if( NULL != stag ) { + if( 0 != strcmp( stag, etag ) ) { + snprintf( error, sizeof( error ), + "mismatched tag, start-tag <%s>, end-tag <%s>", stag, etag ); + } + free( stag ); + } else { + snprintf( error, sizeof( error ), + "mismatched tag, start-tag <NULL>, end-tag <%s>", etag ); + } + + if( '\0' != *error ) { + setError( error ); + delete event; + event = NULL; + } + } + + if( NULL != event ) { + if( SP_XmlPullEvent::eDocDecl == event->getEventType() ) { + snprintf( mEncoding, sizeof( mEncoding ), "%s", + ((SP_XmlDocDeclEvent*)event)->getEncoding() ); + } + mEventQueue->enqueue( event ); + if( mTagNameStack->getCount() <= 0 && eRootStart == mRootTagState ) { + mRootTagState = eRootEnd; + mEventQueue->enqueue( new SP_XmlEndDocEvent() ); + } + } + } + + //printf( "\nchange: %s -> %s\n", typeid( *mReader ).name(), typeid( *reader ).name() ); + + mReaderPool->save( mReader ); + mReader = reader; +} + +SP_XmlReader * SP_XmlPullParser :: getReader( int type ) +{ + return mReaderPool->borrow( type ); +} + +void SP_XmlPullParser :: setError( const char * error ) +{ + if( NULL != error ) { + if( NULL != mError ) free( mError ); + + char segment[ 2 * sizeof( mErrorSegment ) + 1 ]; + { + memset( segment, 0, sizeof( segment ) ); + + char temp[ sizeof( mErrorSegment ) + 1 ]; + memset( temp, 0, sizeof( temp ) ); + if( mErrorIndex < (int)sizeof( mErrorSegment ) ) { + strncpy( temp, mErrorSegment, mErrorIndex ); + } else { + int offset = mErrorIndex % sizeof( mErrorSegment ); + strncpy( temp, mErrorSegment + offset, sizeof( mErrorSegment ) - offset ); + strncpy( temp + sizeof( mErrorSegment ) - offset, mErrorSegment, offset ); + } + + for( char * pos = temp, * dest = segment; '\0' != *pos; pos++ ) { + if( '\r' == *pos ) { + *dest++ = '\\'; + *dest++ = 'r'; + } else if( '\n' == *pos ) { + *dest++ = '\\'; + *dest++ = 'n'; + } else if( '\t' == *pos ) { + *dest++ = '\\'; + *dest++ = 't'; + } else { + *dest++ = *pos; + } + } + } + + char msg[ 512 ]; + snprintf( msg, sizeof( msg), "%s ( occured at row(%d), col(%d) : %s )", + error, mRowIndex + 1, mColIndex + 1, segment ); + + mError = strdup( msg ); + } +} +