Embedded system Fun Blog
























































Find out all the best information, libraries and circuit about the latest Embedded systems.

Sunday, 8 January 2012

MBED: FastXML parser library

.from: http://mbed.org/users/rolf/programs/fastxml/gpdz45

XxXxXxXxXxXxXxXxXxXxXxXxXxXxXx fastxml.cpp XxXxXxXxXxXxXxXxXxXxXxXxXxXxXx

#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;
}

XxXxXxXxXxXxXxXxXxXxXxXxXxXxXx fastxml.h XxXxXxXxXxXxXxXxXxXxXxXxXxXxXx

#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

XxXxXxXxXxXxXxXxXxXxXxXxXxXxXx main.cpp XxXxXxXxXxXxXxXxXxXxXxXxXxXxXx

#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);
    }
}
XxXxXxXxXxXxXxXxXxXxXxXxXxXxXx EOF XxXxXxXxXxXxXxXxXxXxXxXxXxXxXx

No comments:

Post a Comment