SXML Parser

Oi, it’s done I guess. Beta phase though, but it seems to work rather well! This code parses the “SXML” of the post right before this one.

It’s tested with this file:

<window 100 456 789 120 windone SimpleXML>
  <button 101 258 369 123 buttone Ok 1337/>
  <button 102 258 369 123 buttwo Cancel 1338/>
</>

<window 103 456 789 120 windtwo SimpleXML1>
  <window 104 456 789 120 windthree SimpleXML2>
    <button 105 258 369 123 buttwo yes 1339/>
    <button 106 258 369 123 buttwo nay 1340/>
  </>
  <button 106 258 369 123 buttwo nay 1340/>
</>

/*Free to do anything (with this source file) but leave this comment block alone!
  Created by .simplicity's Nick Overdijk (nick@dotsimplicity.net)
*/
#include <iostream>
#include <cstdio>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <stack>
using namespace std;

/*Load file into memory as string
  create vector of element pointers
  parse the document, create elements on the fly
*/

class element {
public:
    element();

    element(string &amp;amp;amp;amp;type, unsigned int x, unsigned int y, unsigned int height, unsigned int width, element *parent) :
    type(type), x(x), y(y), height(height), width(width), parent(parent) {
    }

    element(string &amp;amp;amp;amp;attributes) :
    attributes(attributes) {
        attributeStream.str(attributes);
        parse();
    }

    virtual ~element(){ cout << "Finishing element" << endl; }

    virtual void printInfo() {
        cout << "---" << type << " @ " << this << "---" << endl;
        cout << "Width: " << width << endl;
        cout << "Height: " << height << endl;
        cout << "x: " << x << endl;
        cout << "y: " << y << endl;
        if(parent != NULL)
        cout << "Parent: " << parent << "(" << parent->type << "::" << parent->name << ")" << endl;
    }

    void printTree() {
        printInfo();
        if (parent != NULL) {
            parent->printTree();
        }
    }

    virtual void parse(){
        attributeStream >> type;
        attributeStream >> x;
        attributeStream >> y;
        attributeStream >> width;
        attributeStream >> height;
    }

    void setParent(element *parent){
        this->parent = parent;
    }

    string name;
    string type;
    string attributes;
    stringstream attributeStream;
    unsigned int x;
    unsigned int y;
    unsigned int height;
    unsigned int width;
    element *parent;
};

class button : public element {
    public:
    button(string &amp;amp;amp;amp;attributes) :
    element(attributes) {
        parse();
    }

    virtual ~button() { cout << endl; }

    virtual void parse(){
        attributeStream >> name;
        attributeStream >> caption;
        attributeStream >> style;
    }

    virtual void printInfo(){
        element::printInfo();
        cout << "Name: " << name << endl;
        cout << "Caption: " << caption << endl;
        cout << "Style: " << style << endl;
    }

    string caption;
    int style;
};

class window : public element {
    public:
    window(string &amp;amp;amp;amp;attributes) :
    element(attributes) {
        parse();
    }

    virtual ~window() { cout << endl; }

    virtual void parse(){
        attributeStream >> name;
        attributeStream >> title;
    }

    virtual void printInfo(){
        element::printInfo();
        cout << "Name: " << name << endl;
        cout << "Title: " << title << endl;
    }

    string title;
};

element *createElement(string &amp;amp;amp;amp;type, string &amp;amp;amp;amp;attributes){
#define \
createThis(x)\
if(type == #x) return new x(attributes)

    createThis(button);
    else createThis(window);
    else return NULL;
}

/*Each part of the code is divided into:
   Letting the user know what we're doing
   Do it
   Perform a check
   Tell the user fail or done
   exit or continue
  At any given time, the user knows what the program is doing and it helps debugging a lot.
*/

int main(int argc, char *argv[]) {
    vector<element*> elementList;

    cout << "Opening file: ";
    ifstream document;
    document.open("test.sxml", ios::binary);
    if (!document.is_open()) {
        cout << "[fail]" << endl;
        exit(-1);
    } else {
        cout << "[done]" << endl;
    }

    cout << "Getting filesize: ";
    document.seekg(0, ios::end);
    unsigned int docLen = document.tellg();
    document.seekg(0, ios::beg);
    cout << docLen << " bytes. [done]" << endl;

    cout << "Loading file into memory: ";

    char *buf = new char [docLen];
    document.read(buf, docLen);
    if (document.bad()) {
        cout << "[fail]" << endl;
    } else {
        cout << "[done]" << endl;
    }

    cout << "Parsing file for elements: ";
    /*Algorithm:
          Find a '<'
          if nextchar != '/''
              read in data until >
              parse data, create element
              if char before > != '/'
                  push this element as curent parent
          else if nextchar == '/'
              pop the last parent
    */

    stack <element*> parentStack;
    parentStack.push(NULL);
    unsigned int n, i;
    for (i = 0; i < docLen; i++) {
        if (buf[i] == '<') {
            if (buf[i+1] != '/') {
                for(n = i+1; buf[n] != '>' &amp;amp;amp;amp;&amp;amp;amp;amp; buf[n] != '/'; n++);
                unsigned int lineLength = n - i;
                string line(&amp;amp;amp;amp;buf[i+1], lineLength-1);
                //cout << "DEBUG LINE READ: " << line << endl;
                stringstream lineStream(line);
                string type;
                lineStream >> type;
                element *curElem = createElement(type, line);
                curElem->setParent(parentStack.top());

                for (n = i+2; buf[n] != '>'; n++);
                if (buf[n-1] != '/') {
                    parentStack.push(curElem);
                }
                elementList.push_back(curElem);
            } else {
                parentStack.pop();
            }
        }
    }
    cout << "[done]" << endl;

    for (unsigned int n = 0; n < elementList.size(); n++) {
        elementList[n]->printInfo();
    }
    return 0;
}

Sooo, feel free to comment on the code, but make it useful.

One Response to “SXML Parser”

  1. Thanks to the recent laws which were passed the places where smoking is permitted is getting smaller and smaller says:

    I am typically to running a blog and i really recognize your content. The article has actually peaks my interest. I am going to bookmark your website and maintain checking for brand spanking new information.

Leave a Reply