# HG changeset patch # User alpar # Date 1116503202 0 # Node ID 358b707800b83b57471e0a0cf1ee55248a502220 # Parent c69fedfbb9b3c356d7b76250e21e90cbec97b48d A very simple xml parser diff -r c69fedfbb9b3 -r 358b707800b8 xml.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xml.h Thu May 19 11:46:42 2005 +0000 @@ -0,0 +1,442 @@ +/* -*- C++ -*- */ + +#include +#include +#include +#include +#include +#include + +class XmlWriter +{ + std::ostream& os; + int level; + +protected: + void indent(int level) { + os << std::endl; + for(int i=0;i'; + } + void etag(const std::string &_tag) { + os << "'; + } + void itag(const std::string &_tag) { indent();tag(_tag); } + void ietag(const std::string &_tag) { indent();etag(_tag); } + + void beginTag(const std::string &_tag) { + itag(_tag); + level++; + } + void endTag(const std::string &_tag) { + level--; + ietag(_tag); + } + +public: + + void indent() + { + if(level>=0) indent(level); + else level=0; + } + + ///\e + + ///\e + /// + class ContTag + { + XmlWriter &ix; + const std::string _tag; + public: + ///\e + + ///\e + /// + ContTag(XmlWriter &_ix,const std::string &_t) : + ix(_ix), _tag(_t) + { + ix.tag(_tag); + } + ~ContTag() { ix.etag(_tag);} + }; + + class LineTag + { + XmlWriter &ix; + const std::string _tag; + public: + ///\e + + ///\e + /// + LineTag(XmlWriter &_ix,const std::string &_t) : + ix(_ix), _tag(_t) + { + ix.itag(_tag); + } + ~LineTag() { ix.etag(_tag);} + }; + + ///\e + + ///\e + /// + class Tag + { + XmlWriter &ix; + const std::string _tag; + public: + ///\e + + ///\e + /// + Tag(XmlWriter &_ix,const std::string &_t) : + ix(_ix), _tag(_t) + { + ix.beginTag(_tag); + } + ~Tag() { + ix.endTag(_tag); + } + }; + + ///\e + + ///\e + /// + XmlWriter(std::ostream& _os) : os(_os),level(-1) {} + ~XmlWriter() { os<< std::endl; } + + XmlWriter &operator()(int v) + { + if(!(os << v)) throw (std::ios::failure ("data format error")); + return *this; + } + XmlWriter &operator()(const std::string &_tag,int v) + { + LineTag t(*this,_tag); + if(!(os << v)) throw (std::ios::failure ("data format error")); + return *this; + } + XmlWriter &operator()(const std::string &_tag,double v) + { + LineTag t(*this,_tag); + if(os << v) throw (std::ios::failure ("data format error")); + return *this; + } + XmlWriter &operator()(double v) + { + os << v; + return *this; + } + XmlWriter &operator()(const std::string &v) + { + for(std::string::const_iterator i=v.begin();i!=v.end();++i) + switch(*i) { + case '\\': + os << "\\\\"; + break; + case '<': + os << "\\<"; + break; + case '&': + os << "\\&"; + break; + case '\n': + os << "\\n"; + break; + default: + os<<*i; + break; + } + return *this; + } + XmlWriter &operator()(const std::string &_tag,const std::string &v) + { + LineTag t(*this,_tag); + (*this)(v); + return *this; + } + ///\e + + ///\e + /// + template + XmlWriter &operator()(const std::string &_tag,const V &v) + { + Tag t(*this,_tag); + out(*this,v); + return *this; + } + ///\e + + ///\e + /// + template + XmlWriter &operator()(const V &v) + { + out(*this,v); + return *this; + } +}; + +////////////////////////////////////////////////////////////////////// + +class XmlReader +{ + std::istream& is; + + std::string next_tag; + void skipWhiteSpaces() + { + char c; + while (is.get(c) && std::isspace(c,is.getloc())); + is.unget(); + } +protected: + ///\e + + ///\e + /// + void useTag() {next_tag.clear();} + + void useTag(const std::string &_tag) { + if(nextTag()==_tag) useTag(); + else throw (std::ios::failure ("data format error")); + } +public: + ///\e + + ///\e + /// + const std::string &nextTag() + { + if(next_tag.empty()) { + char c; + skipWhiteSpaces(); + if(!is.get(c) || c!='<') + throw (std::ios::failure ("data format error")); + next_tag.clear(); + while (is.get(c) && c!='>') next_tag.push_back(c); + if(c!='>') + throw (std::ios::failure ("data format error")); + } + return next_tag; + } + + ///\e + + ///\e + /// + class Tag + { + XmlReader &ix; + const std::string tag; + public: + ///\e + + ///\e + /// + Tag(XmlReader &_ix,const std::string &_tag) : + ix(_ix), tag(_tag) + { + ix.useTag(_tag); + } + ~Tag() { + if(!std::uncaught_exception()) + ix.useTag('/'+tag); + } + }; + + ///\e + + ///\e + /// + XmlReader(std::istream& _is) : is(_is) {} + + int operator()(const std::string &tag,int &v) + { + Tag t(*this,tag); + if(!(is >> v)) throw (std::ios::failure ("data format error")); + return v; + } + double operator()(const std::string &tag,double &v) + { + Tag t(*this,tag); + if(!(is >> v)) throw (std::ios::failure ("data format error")); + return v; + } + std::string &operator()(const std::string &tag,std::string &v) + { + Tag t(*this,tag); + v.clear(); + char c; + while (is.get(c) && c!='<') + if(c=='\\') + if(!is.get(c)) throw (std::ios::failure ("data format error")); + else switch(c) { + case 'n': + v.push_back('\n'); + break; + default: + v.push_back(c); + break; + } + else v.push_back(c); + if(c!='<') + throw (std::ios::failure ("data format error")); + is.unget(); + return v; + } + ///\e + + ///\e + /// + template + V &operator()(const std::string &tag,V &v) + { + Tag t(*this,tag); + in(*this,v); + return v; + } + ///\e + + ///\e + /// + template + V &operator()(V &v) + { + in(*this,v); + return v; + } + ///\e + + ///\e + /// + template + V load(const std::string &tag) + { + Tag t(*this,tag); + V v; + (*this)(tag,v); + return v; + } +}; + +////////////////////////////////////////////////////////////////////// + +template +void out(XmlWriter &i,const std::pair &v) +{ + i("first",v.first); + i("second",v.second); +} + +template +void in(XmlReader &i,std::pair &v) +{ + i("first",v.first); + i("second",v.second); +} + +////////////////////////////// + +template +void out(XmlWriter &i,const std::list &v) +{ + for(typename std::list::const_iterator it=v.begin(); + it!=v.end();++it) i("item",*it); +} + +template +void in(XmlReader &i,std::list &v) +{ + while(i.nextTag()=="item") + { + v.push_back(T()); + i("item",v.back()); + } +} + +////////////////////////////// + +template +void out(XmlWriter &i,const std::vector &v) +{ + for(typename std::vector::const_iterator it=v.begin(); + it!=v.end();++it) i("item",*it); +} + +template +void in(XmlReader &i,std::vector &v) +{ + while(i.nextTag()=="item") + { + v.push_back(T()); + i("item",v.back()); + } +} + +////////////////////////////// + +template +void out(XmlWriter &i,const std::map &v) +{ + for(typename std::map::const_iterator it=v.begin(); + it!=v.end();++it) i("item",*it); +} + +template +void in(XmlReader &i,std::map &v) +{ + while(i.nextTag()=="item") + { + typename std::map::value_type it; + i("item",it); + v.insert(it); + } +} + +////////////////////////////// + +template +void out(XmlWriter &i,const lemon::xy &v) +{ +// i("x",v.x); +// i("y",v.y); + { XmlWriter::LineTag t(i,"x"); i(v.x); } + { XmlWriter::ContTag t(i,"y"); i(v.y); } +} + +template +void in(XmlReader &i,lemon::xy &v) +{ + i("x",v.x); + i("y",v.y); +} + +////////////////////////////// + +template +void out(XmlWriter &i,const lemon::BoundingBox &v) +{ + if(!v.empty()) { + i("point",v.bottomLeft()); + if(v.bottomLeft()!=v.topRight()) i("point",v.topRight()); + } +} + +template +void in(XmlReader &i,lemon::BoundingBox &v) +{ + v.clear(); + while(i.nextTag()=="point") { + lemon::xy co; + i("point",co); + v+=co; + } +}