This demo contains a port of the FastXML library. FastXML was hosted on geocities and is offline now. The library itself is contained into two files header and cpp and very easy to use. I don't know how many RAM it eats up but XML is probably not the best thing to use on an microcontroler. Decide your self but be warned. I told you so!!
Revision 0:37e8c5cd04e8, committed 2009-12-11
- Comitter:
- rolf
- Date:
- Fri Dec 11 15:32:41 2009 +0000
- Commit message:
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fastxml/fastxml.cpp Fri Dec 11 15:32:41 2009 +0000 @@ -0,0 +1,330 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "fastxml.h" + +/*! +** +** Copyright (c) 2009 by John W. Ratcliff mailto:jratcliffscarab@gmail.com +** +** The MIT license: +** +** Permission is hereby granted, MEMALLOC_FREE of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is furnished +** to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in all +** copies or substantial portions of the Software. + +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + + +class MyFastXml : public FastXml { +public: + enum CharType { + CT_DATA, + CT_EOF, + CT_SOFT, + CT_END_OF_ELEMENT, // either a forward slash or a greater than symbol + CT_END_OF_LINE, + }; + + MyFastXml(void) { + mInputData = 0; + memset(mTypes,CT_DATA,256); + mTypes[0] = CT_EOF; + mTypes[32] = CT_SOFT; + mTypes[9] = CT_SOFT; + mTypes['/'] = CT_END_OF_ELEMENT; + mTypes['>'] = CT_END_OF_ELEMENT; + mTypes['?'] = CT_END_OF_ELEMENT; + mTypes[10] = CT_END_OF_LINE; + mTypes[13] = CT_END_OF_LINE; + mError = 0; + } + ~MyFastXml(void) { + release(); + } + + void release(void) { + if(mInputData) { + free(mInputData); + mInputData = 0; + } + mError = 0; + } + + inline char *nextSoft(char *scan) { + while ( *scan && mTypes[*scan] != CT_SOFT ) scan++; + return scan; + } + + inline char *nextSoftOrClose(char *scan,bool &close) { + while ( *scan && mTypes[*scan] != CT_SOFT && *scan != '>' ) scan++; + close = *scan == '>'; + return scan; + } + + inline char *nextSep(char *scan) { + while ( *scan && mTypes[*scan] != CT_SOFT && *scan != '=' ) scan++; + return scan; + } + + inline char * skipNextData(char *scan) { + // while we have data, and we encounter soft seperators or line feeds... + while ( *scan && mTypes[*scan] == CT_SOFT || mTypes[*scan] == CT_END_OF_LINE ) { + if ( *scan == 13 ) mLineNo++; + scan++; + } + return scan; + } + + char * processClose(char c,const char *element,char *scan,int argc,const char **argv,FastXmlInterface *iface) { + if ( c == '/' || c == '?' ) { + if ( *scan != '>' ) { // unexepected character! + mError = "Expected an element close character immediately after the '/' or '?' character."; + return 0; + } + scan++; + bool ok = iface->processElement(element,argc,argv,0,mLineNo); + if ( !ok ) + { + mError = "User aborted the parsing process"; + return 0; + } + } + else + { + scan = skipNextData(scan); + char *data = scan; // this is the data portion of the element, only copies memory if we encounter line feeds + char *dest_data = 0; + while ( *scan && *scan != '<' ) + { + if ( mTypes[*scan] == CT_END_OF_LINE ) + { + if ( *scan == 13 ) mLineNo++; + dest_data = scan; + *dest_data++ = 32; // replace the linefeed with a space... + scan = skipNextData(scan); + while ( *scan && *scan != '<' ) + { + if ( mTypes[*scan] == CT_END_OF_LINE ) + { + if ( *scan == 13 ) mLineNo++; + *dest_data++ = 32; // replace the linefeed with a space... + scan = skipNextData(scan); + } + else + { + *dest_data++ = *scan++; + } + } + break; + } + else + scan++; + } + if ( *scan == '<' ) + { + if ( dest_data ) + { + *dest_data = 0; + } + else + { + *scan = 0; + } + scan++; // skip it.. + if ( *data == 0 ) data = 0; + bool ok = iface->processElement(element,argc,argv,data,mLineNo); + if ( !ok ) + { + mError = "User aborted the parsing process"; + return 0; + } + if ( *scan == '/' ) + { + while ( *scan && *scan != '>' ) scan++; + scan++; + } + } + else + { + mError = "Data portion of an element wasn't terminated properly"; + return 0; + } + } + return scan; + } + + virtual bool processXml(const char *inputData,unsigned int dataLen,FastXmlInterface *iface) + { + bool ret = true; + + #define MAX_ATTRIBUTE 2048 // can't imagine having more than 2,048 attributes in a single element right? + + release(); + mInputData = (char *)malloc(dataLen+1); + memcpy(mInputData,inputData,dataLen); + mInputData[dataLen] = 0; + + mLineNo = 1; + + char *element; + + char *scan = mInputData; + if ( *scan == '<' ) + { + scan++; + while ( *scan ) + { + scan = skipNextData(scan); + if ( *scan == 0 ) return ret; + if ( *scan == '<' ) + { + scan++; + } + if ( *scan == '/' || *scan == '?' ) + { + while ( *scan && *scan != '>' ) scan++; + scan++; + } + else + { + element = scan; + int argc = 0; + const char *argv[MAX_ATTRIBUTE]; + bool close; + scan = nextSoftOrClose(scan,close); + if ( close ) + { + char c = *(scan-1); + if ( c != '?' && c != '/' ) + { + c = '>'; + } + *scan = 0; + scan++; + scan = processClose(c,element,scan,argc,argv,iface); + if ( !scan ) return false; + } + else + { + if ( *scan == 0 ) return ret; + *scan = 0; // place a zero byte to indicate the end of the element name... + scan++; + + while ( *scan ) + { + scan = skipNextData(scan); // advance past any soft seperators (tab or space) + + if ( mTypes[*scan] == CT_END_OF_ELEMENT ) + { + char c = *scan++; + scan = processClose(c,element,scan,argc,argv,iface); + if ( !scan ) return false; + break; + } + else + { + if ( argc >= MAX_ATTRIBUTE ) + { + mError = "encountered too many attributes"; + return false; + } + argv[argc] = scan; + scan = nextSep(scan); // scan up to a space, or an equal + if ( *scan ) + { + if ( *scan != '=' ) + { + *scan = 0; + scan++; + while ( *scan && *scan != '=' ) scan++; + if ( *scan == '=' ) scan++; + } + else + { + *scan=0; + scan++; + } + if ( *scan ) // if not eof... + { + scan = skipNextData(scan); + if ( *scan == 34 ) + { + scan++; + argc++; + argv[argc] = scan; + argc++; + while ( *scan && *scan != 34 ) scan++; + if ( *scan == 34 ) + { + *scan = 0; + scan++; + } + else + { + mError = "Failed to find closing quote for attribute"; + return false; + } + } + else + { + mError = "Expected quote to begin attribute"; + return false; + } + } + } + } + } + } + } + } + } + else + { + mError = "Expected the start of an element '<' at this location."; + ret = false; // unexpected character!? + } + + return ret; + } + + virtual const char *getError(int &lineno) { + const char *ret = mError; + lineno = mLineNo; + mError = 0; + return ret; + } + +private: + char mTypes[256]; + char *mInputData; + int mLineNo; + const char *mError; +}; + + + +FastXml *createFastXml(void) { + MyFastXml *f = new MyFastXml; + return static_cast< FastXml *>(f); +} + +void releaseFastXml(FastXml *f) { + MyFastXml *m = static_cast< MyFastXml *>(f); + delete m; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fastxml/fastxml.h Fri Dec 11 15:32:41 2009 +0000 @@ -0,0 +1,81 @@ +#ifndef FAST_XML_H +#define FAST_XML_H + +/*! +** +** Copyright (c) 2009 by John W. Ratcliff mailto:jratcliff@infiniplex.net +** +** The MIT license: +** +** Permission is hereby granted, MEMALLOC_FREE of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is furnished +** to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in all +** copies or substantial portions of the Software. + +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + + +// This code snippet provides an extremely lightweight and fast XML parser. +// This parser only handles data elements as if they were streamed data. +// It is important to note that all pointers returned by this parser are +// persistent for the lifetime of the FastXml class. This means you can cache +// copies of the pointers (rather than copying any data) if this matches your +// needs. + + +// Simpy call createFastXml to get a copy of the FastXml parsing interface +// To parse an XML file, have your application inherit the pure virtual +// interface called 'FastXmlInterface' and implement the single method 'processElement' +// +// For each element in the XML file you will get a callback with the following +// data. +// +// 'elementName' the name of the element (this pointer is persistent) +// 'argc' The total number of attributes and values for this element. +// The number of attribute/value pairs is equal to argc/2 +// 'argv' The attribute/value pairs in the form of attribute/value, attribute/value.. +// These pointers are persistent and can be cached if needed (until FastXml is released) +// 'elementData' optional data (i.e. text) associated with the element. If this is a null pointer +// then the element had no data. This pointer is persistent. +// 'lineno' The line number in the source XML file. +// +// After calling your routine 'processElement' you must return 'true' to continue parsing +// If you want to stop parsing early, return false. +// +// If the call to process an XML file fails, it will return false. +// You can then call the method 'getError' to get a description of why it failed +// and on what line number of the source XML file it occurred. + +class FastXmlInterface { + public: + // return true to continue processing the XML document, false to skip. + virtual bool processElement(const char *elementName, // name of the element + int argc, // number of attributes + const char **argv, // list of attributes. + const char *elementData, // element data, null if none + int lineno) = 0; // line number in the source XML file + +}; + +class FastXml { + public: + virtual bool processXml(const char *inputData,unsigned int dataLen,FastXmlInterface *iface) = 0; + virtual const char * getError(int &lineno) = 0; // report the reason for a parsing error, and the line number where it occurred. +}; + +FastXml *createFastXml(void); +void releaseFastXml(FastXml *f); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Fri Dec 11 15:32:41 2009 +0000 @@ -0,0 +1,38 @@ +#include "mbed.h" +#include "fastxml.h" + +DigitalOut myled(LED1); + +class tmpr : public FastXmlInterface { + public: + virtual bool processElement(const char *name, int argc, const char **argv, const char *data, int lineno) { + printf("::%s\n", name); + if(strncmp(name, "tmpr", 4)==0) { + printf("tmpr: %s\n", data); + } + return true; + } +}; + +const char *code = { + "<root>\r\n" + " <chan1>\r\n" + " <tmpr>23.7</tmpr>\r\n" + " </chan1>\r\n" + " <chan2>\r\n" + " <tmpr>23.7</tmpr>\r\n" + " </chan2>\r\n" + "</root>\r\n" +}; + +int main() { + FastXml *xml = createFastXml(); + FastXmlInterface *tmp = new tmpr(); + xml->processXml(code, strlen(code), tmp); + while(1) { + myled = 1; + wait(0.2); + myled = 0; + wait(0.2); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Fri Dec 11 15:32:41 2009 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0