Subversion Repositories gelsvn

Rev

Rev 375 | Rev 377 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <fstream>
#include <string>
#include <sstream>
#include <cstring>
#include <algorithm>
#include <list>
#include "XmlParser.h"
#include "string_utils.h"

using namespace std;

namespace Util
{
  /////////////////////////////////////////////////////////////////
  // String handling
  /////////////////////////////////////////////////////////////////

  void parse_attribs(const string& s, map<string, string>& result)
  {
    string name1, name2;
    list<string> atts;
    trim_split(s, atts, "=");
    if(atts.empty())
      return;

    get_last(atts.front(), name1);
    list<string>::iterator i = atts.begin();
    list<string>::iterator end = atts.end();
    if(i == --end)
      return;
    
    for(++i; i != end; ++i)
    { 
      get_last(*i, name2);
      result[trim(name1)] = trim(*i, " \"");
      name1 = name2;
    }
    result[trim(name1)] = trim(*end, " \"");
  }

  /////////////////////////////////////////////////////////////////
  // File handling
  /////////////////////////////////////////////////////////////////

  ifstream& seek_string(ifstream& in, const string& s, const size_t bufsize = 100)
  {
    const int bsize = static_cast<int>(max(s.size(), bufsize));
    const int n = static_cast<int>(s.size());
    char* buf = new char[bsize + 1];
    char s0 = s[0];

    in.get(buf, bsize, s0);
    in.clear();
    in.read(buf, n);
    buf[n] = '\0'; 
    while(in && strcmp(s.c_str(), buf) != 0)
    {
      in.get(buf, bsize, s0);
      in.clear();
      in.read(buf, n);
      buf[n] = '\0'; 
    }
    
    delete [] buf;
    return in;
  }

  ifstream& read_until(ifstream& in, string& s_in, const string s, const size_t bufsize = 500)
  {
    const int bsize = static_cast<int>(max(s.size(), bufsize));
    const int n = static_cast<int>(s.size());
    char* buf = new char[bsize + 1];
    char s0 = s[0];
    ostringstream ostr;

    in.get(buf, bsize, s0);
    ostr << buf;
    in.clear();
    in.read(buf, n);
    buf[n] = '\0'; 
    while(in && strcmp(s.c_str(), buf) != 0)
    {
      ostr << buf;
      in.get(buf, bsize, s0);
      ostr << buf;
      in.clear();
      in.read(buf, n);
      buf[n] = '\0'; 
    }
    s_in = ostr.str();

    delete [] buf;
    return in;
  }

  ifstream& operator>>(ifstream& in, XmlHead& fhead)
  {
    seek_string(in, "<?xml");

    string head;
    read_until(in, head, "?>");

    fhead.is_xml = in.good();
    parse_attribs(head, fhead.atts);

    return in;
  }

  ifstream& operator>>(ifstream& in, XmlElement& elem)
  {
    seek_string(in, "<");

    string head;
    read_until(in, head, ">");

    if(head[0] == '!') return in;

    bool has_body = true;
    if(head[head.size() - 1] == '/')
    {
      has_body = false;
      head.erase(head.size() - 1);
    }

    get_first(head, elem.name);
    parse_attribs(head, elem.atts);

    if(has_body)
    {
      delete elem.body;
      elem.body = new XmlBody(elem.doc);
      string body;
      while(read_until(in, body, "<"))
      {
        elem.body->text.push_back(body);

        char c;
        in >> c;
        if(c == '/')
        {
          string closing;
          read_until(in, closing, ">");
          if(trim(closing) == elem.name)
            break;
        }
        in.putback(c);
        in.putback('<');

        elem.body->elements.push_back(XmlElement(elem.doc, &elem));
        if(!(in >> elem.body->elements.back()))
        {
          elem.body->elements.pop_back();
          break;
        }
      }      
    }
    return in;
  }

  ifstream& operator>>(ifstream& in, XmlBody& body)
  {
    string s;
    while(read_until(in, s, "<"))
    {
      body.text.push_back(s);

      in.putback('<');

      body.elements.push_back(XmlElement(body.doc));
      if(!(in >> body.elements.back()))
      {
        body.elements.pop_back();
        break;
      }
    }      
    return in;
  }

  void XmlDoc::load_xml(const char *filename)
  {
    ifstream infile(filename);

    if(!infile)
    {
       cerr << "cannot open input file" << filename << endl;
       return;
    }
    
    if(infile >> head)
      infile >> body;
    else
      cerr << filename << " is not a valid xml-file" << endl;

    infile.close();    
  }

  /////////////////////////////////////////////////////////////////
  // Methods
  /////////////////////////////////////////////////////////////////

  XmlElement::~XmlElement()
  {
    delete body;
  }

  void XmlElement::process_element(XmlElement& elem)
  {
    if(!doc) return;
    XmlElementHandler h = doc->handlers[elem.name];
    if(h) h(elem);
  }

  void XmlElement::process_elements()
  {
    if(!body) return;
    if(!doc) return;

    XmlElementHandler h = 0;
    for(list<XmlElement>::iterator i = body->elements.begin(); i != body->elements.end(); ++i)
      if(h = doc->handlers[(*i).name])
         h(*i);
  }

  XmlDoc::XmlDoc(const char *filename)
    : body(0)
  {
    body.doc = this;
    load_xml(filename);
  }

  void XmlDoc::process_elements()
  {
    XmlElementHandler h = 0;
    for(list<XmlElement>::iterator i = body.elements.begin(); i != body.elements.end(); ++i)
      if(h = handlers[(*i).name])
         h(*i);
  }

  ostream& XmlDoc::put(ostream& out) const
  {
    return out << head << body;    
  }

  /////////////////////////////////////////////////////////////////
  // Output handling
  /////////////////////////////////////////////////////////////////

  ostream& operator<<(ostream& out, const pair<string, string>& attrib)
  {
    return out << attrib.first << "=\"" << attrib.second << "\"";
  }

  ostream& operator<<(ostream& out, const XmlHead& head)
  {
    out << "<?xml";
    for(map<string, string>::const_iterator i = head.atts.begin(); i != head.atts.end(); ++i)
      out << " " << *i;
    out << "?>";
    return out;
  }

  ostream& operator<<(ostream& out, const XmlElement& elem)
  {
    out << "<" << elem.name;
    for(map<string, string>::const_iterator i = elem.atts.begin(); i != elem.atts.end(); ++i)
      out  << " " << *i;
    out << (elem.body ? ">" : "/>");

    if(elem.body)
      out << *elem.body << "</" << elem.name << ">";

    return out;
  }

  ostream& operator<<(ostream& out, const XmlBody& body)
  {
    list<string>::const_iterator i = body.text.begin();
    list<XmlElement>::const_iterator j = body.elements.begin();
    for(; i != body.text.end() && j != body.elements.end(); ++i, ++j)
      out << *i << *j;
    return out << (body.text.empty() ? "" : body.text.back());
  }
}

Generated by GNU Enscript 1.6.6.