diff -r 0e4f009eab8b -r 67188bd752db xml.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xml.h Mon Jul 07 08:10:39 2008 -0500 @@ -0,0 +1,448 @@ +/* -*- C++ -*- + * + * This file is a part of LEMON, a generic C++ optimization library + * + * Copyright (C) 2003-2006 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +#ifndef GLEMON_XML_H +#define GLEMON_XML_H + +#include +#include +#include +#include +#include +#include +#include + +namespace lemon { + + class XmlIo + { + bool _writeMode; + public: + ///Check if XmlIo is in write mode. + bool write() { return _writeMode;} + ///Check if XmlIo is in read mode. + bool read() { return !_writeMode;} + + 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: + ///Indent the line according to its level. + + ///\warning It can only be used in write mode. + /// + void indent() + { + if(write()) + if(level>=0) indent(level); + else level=0; + else throw LogicError(); + } + + ///Read/write a tag + + ///Read/write a tag. + ///In write mode it does not start a new line. + class ContTag + { + XmlIo &ix; + const std::string _tag; + public: + ///\e + + ///\e + /// + ContTag(XmlIo &_ix,const std::string &_t) : + ix(_ix), _tag(_t) + { + if(ix.write()) ix.tag(_tag); + else ix.useTag(_tag); + } + ~ContTag() { + if(ix.write()) ix.etag(_tag); + else if(!std::uncaught_exception()) ix.useTag('/'+_tag); + } + }; + + ///Read/write a tag + + ///Read/write a tag. + ///The whole \ ... \ will be placed in a single line. + class LineTag + { + XmlIo &ix; + const std::string _tag; + public: + ///\e + + ///\e + /// + LineTag(XmlIo &_ix,const std::string &_t) : + ix(_ix), _tag(_t) + { + if(ix.write()) ix.itag(_tag); + else ix.useTag(_tag); + } + ~LineTag() { + if(ix.write()) ix.etag(_tag); + else if(!std::uncaught_exception()) ix.useTag('/'+_tag); + } + }; + + ///Read/write a tag + + ///Read/write a tag. + /// + class Tag + { + XmlIo &ix; + const std::string _tag; + public: + ///\e + + ///\e + /// + Tag(XmlIo &_ix,const std::string &_t) : + ix(_ix), _tag(_t) + { + if(ix.write()) ix.beginTag(_tag); + else ix.useTag(_tag); + } + ~Tag() { + if(ix.write()) ix.endTag(_tag); + else if(!std::uncaught_exception()) ix.useTag('/'+_tag); + } + }; + + private: + std::istream& is; + std::string next_tag; + int line_number; + + void skipWhiteSpaces() + { + if(write()) throw LogicError(); + { + char c; + while (is.get(c) && std::isspace(c,is.getloc())) + if(c=='\n') line_number++; + is.unget(); + } + } + protected: + /// Use the next tag. + + ///\e + /// + void useTag() {next_tag.clear();} + + ///Use the next tag and check if it is equal with \c _tag + + ///\e + /// + void useTag(const std::string &_tag) { + if(nextTag()==_tag) useTag(); + else throw DataFormatError("",line_number,"Unexpected token name"); + } + public: + ///Return the next tag (if a tag follows on the stream). + + ///\warning It can only be used in read mode. + /// + const std::string &nextTag() + { + if(write()) throw LogicError(); + else if(next_tag.empty()) { + char c; + skipWhiteSpaces(); + if(!is.get(c) || c!='<') + throw DataFormatError("",line_number,"Bad format"); + next_tag.clear(); + while (is.get(c) && c!='>') next_tag.push_back(c); + if(c!='>') + throw DataFormatError("",line_number,"Bad format"); + } + return next_tag; + } + + /**********************************************************************/ + + + ///\e + + ///\e + /// + XmlIo(std::ostream& _os) : _writeMode(true), os(_os), + level(-1), + is(std::cin) {} + ///\e + /// + XmlIo(std::istream& _is) : _writeMode(false), + os(std::cout), is(_is), + line_number(1) {} + + ~XmlIo() { if(write()) os<< std::endl; } + + + + XmlIo &operator()(const int &v) + { + if(write()) os << v; + else { + skipWhiteSpaces(); + if(!(is >> const_cast(v))) + throw DataFormatError("",line_number,"Not an 'int'"); + } + return *this; + } + XmlIo &operator()(const double &v) + { + if(write()) os << v; + else { + skipWhiteSpaces(); + if(!(is >> const_cast(v))) + throw DataFormatError("",line_number,"Not an 'double'"); + } + return *this; + } + XmlIo &operator()(const std::string &v) + { + if(write()) + 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; + } + else { + std::string &w = const_cast(v); + w.clear(); + char c; + while (is.get(c) && c!='<') + if(c=='\\') + if(!is.get(c)) + throw DataFormatError("",line_number,"Bad string"); + else switch(c) { + case 'n': + w.push_back('\n'); + break; + default: + w.push_back(c); + break; + } + else { + if(c=='\n') line_number++; + w.push_back(c); + } + if(c!='<') + throw DataFormatError("",line_number,"Unexpected eof"); + is.unget(); + } + return *this; + } + + + XmlIo &operator()(const std::string &_tag,const int &v) + { + LineTag t(*this,_tag); + (*this)(v); + return *this; + } + XmlIo &operator()(const std::string &_tag,const double &v) + { + LineTag t(*this,_tag); + (*this)(v); + return *this; + } + XmlIo &operator()(const std::string &_tag,const std::string &v) + { + LineTag t(*this,_tag); + (*this)(v); + return *this; + } + ///\e + + ///\e + /// + template + XmlIo &operator()(const std::string &_tag,const V &v) + { + Tag t(*this,_tag); + xml(*this,const_cast(v)); + return *this; + } + ///\e + + ///\e + /// + template + XmlIo &operator()(const V &v) + { + xml(*this,const_cast(v)); + return *this; + } + }; + + ////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////// + + ///\e + + ///\relates XmlIo + /// + template + void xml(XmlIo &x,std::auto_ptr &v) + { + if(x.write()) v=new A; + x(*v); + } + + ///\e + + ///\relates XmlIo + /// + template + void xml(XmlIo &x,std::pair &v) + { + x("first",v.first); + x("second",v.second); + } + + ///\e + + ///\relates XmlIo + /// + template + void xml(XmlIo &x,std::list &v) + { + if(x.write()) + for(typename std::list::const_iterator it=v.begin(); + it!=v.end();++it) x("item",*it); + else while(x.nextTag()=="item") + { + v.push_back(T()); + x("item",v.back()); + } + } + ///\e + + ///\relates XmlIo + /// + template + void xml(XmlIo &x,std::vector &v) + { + if(x.write()) + for(typename std::vector::const_iterator it=v.begin(); + it!=v.end();++it) x("item",*it); + else while(x.nextTag()=="item") + { + v.push_back(T()); + x("item",v.back()); + } + } + + ///\e + + ///\relates XmlIo + /// + template + void xml(XmlIo &x,std::map &v) + { + if(x.write()) + for(typename std::map::const_iterator it=v.begin(); + it!=v.end();++it) x("item",*it); + else while(x.nextTag()=="item") + { + typename std::map::value_type it; + x("item",it); + v.insert(it); + } + } + + ///\e + + ///\relates XmlIo + /// + template + void xml(XmlIo &x,lemon::dim2::Point &v) + { + { XmlIo::LineTag t(x,"x"); x(v.x); } + { XmlIo::ContTag t(x,"y"); x(v.y); } + } + + ///\e + + ///\relates XmlIo + /// + template + void xml(XmlIo &x,lemon::dim2::BoundingBox &v) + { + if(x.write()) { + if(!v.empty()) { + x("point",v.bottomLeft()); + if(v.bottomLeft()!=v.topRight()) x("point",v.topRight()); + } + } + else { + v.clear(); + while(x.nextTag()=="point") { + lemon::dim2::Point co; + x("point",co); + v.add(co); + } + } + } + +} + +#endif