xml.h
author ladanyi
Wed, 02 May 2007 20:33:58 +0000
changeset 200 c7ae8642a8d8
parent 150 86273bfe0e4d
child 201 879e47e5b731
permissions -rw-r--r--
Bugfix.
     1 /* -*- C++ -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library
     4  *
     5  * Copyright (C) 2003-2006
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     9  * Permission to use, modify and distribute this software is granted
    10  * provided that this copyright notice appears in all copies. For
    11  * precise terms see the accompanying LICENSE file.
    12  *
    13  * This software is provided "AS IS" with no warranty of any kind,
    14  * express or implied, and with no claim as to its suitability for any
    15  * purpose.
    16  *
    17  */
    18 
    19 #include <iostream>
    20 #include <string>
    21 #include <vector>
    22 #include <list>
    23 #include <map>
    24 #include <lemon/error.h>
    25 #include <lemon/dim2.h>
    26 
    27 namespace lemon {
    28 
    29   class XmlIo 
    30   {
    31     bool _writeMode;
    32   public:
    33     ///Check if XmlIo is in write mode.
    34     bool write() { return _writeMode;}
    35     ///Check if XmlIo is in read mode.
    36     bool read() { return !_writeMode;}
    37 
    38     std::ostream& os;
    39     int level;
    40     
    41   protected:
    42     void indent(int level) {
    43       os << std::endl;
    44       for(int i=0;i<level;i++) os << ' ';
    45     }
    46     void tag(const std::string &_tag) {
    47       os << '<' << _tag << '>';
    48     }
    49     void etag(const std::string &_tag) {
    50       os << "</" << _tag << '>';
    51     }
    52     void itag(const std::string &_tag) { indent();tag(_tag); }
    53     void ietag(const std::string &_tag) { indent();etag(_tag); }
    54 
    55     void beginTag(const std::string &_tag) {
    56       itag(_tag);
    57       level++;
    58     }
    59     void endTag(const std::string &_tag) {
    60       level--;
    61       ietag(_tag);
    62     }
    63 
    64   public:
    65     ///Indent the line according to its level.
    66 
    67     ///\warning It can only be used in write mode.
    68     ///
    69     void indent()
    70     {
    71       if(write())
    72 	if(level>=0) indent(level);
    73 	else level=0;
    74       else throw LogicError();	
    75     }
    76   
    77     ///Read/write a tag
    78   
    79     ///Read/write a tag.
    80     ///In write mode it does not start a new line.
    81     class ContTag
    82     {
    83       XmlIo &ix;
    84       const std::string _tag;
    85     public:
    86       ///\e
    87   
    88       ///\e
    89       ///
    90       ContTag(XmlIo &_ix,const std::string &_t) :
    91 	ix(_ix), _tag(_t)
    92       {
    93 	if(ix.write()) ix.tag(_tag);
    94 	else ix.useTag(_tag);
    95       }
    96       ~ContTag() { 
    97 	if(ix.write()) ix.etag(_tag);
    98 	else if(!std::uncaught_exception()) ix.useTag('/'+_tag);      
    99       }
   100     };
   101 
   102     ///Read/write a tag
   103   
   104     ///Read/write a tag.
   105     ///The whole \<foo\> ... \</foo\> will be placed in a single line.
   106     class LineTag
   107     {
   108       XmlIo &ix;
   109       const std::string _tag;
   110     public:
   111       ///\e
   112     
   113       ///\e
   114       ///
   115       LineTag(XmlIo &_ix,const std::string &_t) :
   116 	ix(_ix), _tag(_t)
   117       {
   118 	if(ix.write()) ix.itag(_tag);
   119 	else ix.useTag(_tag);
   120       }
   121       ~LineTag() { 
   122 	if(ix.write()) ix.etag(_tag);
   123 	else if(!std::uncaught_exception()) ix.useTag('/'+_tag);
   124       }
   125     };
   126 
   127     ///Read/write a tag
   128   
   129     ///Read/write a tag.
   130     ///
   131     class Tag
   132     {
   133       XmlIo &ix;
   134       const std::string _tag;
   135     public:
   136       ///\e
   137   
   138       ///\e
   139       ///
   140       Tag(XmlIo &_ix,const std::string &_t) :
   141 	ix(_ix), _tag(_t)
   142       {
   143 	if(ix.write()) ix.beginTag(_tag);
   144 	else ix.useTag(_tag);
   145       }
   146       ~Tag() {
   147 	if(ix.write()) ix.endTag(_tag);
   148 	else if(!std::uncaught_exception()) ix.useTag('/'+_tag);
   149       }
   150     };
   151 
   152   private:
   153     std::istream& is;
   154     std::string next_tag;
   155     int line_number;
   156 
   157     void skipWhiteSpaces()
   158     {
   159       if(write()) throw LogicError();
   160       {
   161 	char c;
   162 	while (is.get(c) && std::isspace(c,is.getloc()))
   163 	  if(c=='\n') line_number++;
   164 	is.unget();
   165       }
   166     }
   167   protected:
   168     /// Use the next tag.
   169 
   170     ///\e
   171     ///
   172     void useTag() {next_tag.clear();}
   173   
   174     ///Use the next tag and check if it is equal with \c _tag
   175   
   176     ///\e
   177     ///
   178     void useTag(const std::string &_tag) {
   179       if(nextTag()==_tag) useTag();
   180       else throw DataFormatError("",line_number,"Unexpected token name");
   181     }
   182   public:
   183     ///Return the next tag (if a tag follows on the stream).
   184   
   185     ///\warning It can only be used in read mode.
   186     ///
   187     const std::string &nextTag() 
   188     {
   189       if(write()) throw LogicError();
   190       else if(next_tag.empty()) {
   191 	char c;
   192 	skipWhiteSpaces();
   193 	if(!is.get(c) || c!='<')
   194 	  throw DataFormatError("",line_number,"Bad format");
   195 	next_tag.clear();
   196 	while (is.get(c) && c!='>') next_tag.push_back(c);
   197 	if(c!='>')
   198 	  throw DataFormatError("",line_number,"Bad format");
   199       }
   200       return next_tag;
   201     }
   202 
   203     /**********************************************************************/
   204 
   205 
   206     ///\e
   207   
   208     ///\e
   209     ///
   210     XmlIo(std::ostream& _os) : _writeMode(true), os(_os),
   211 			       level(-1),
   212 			       is(std::cin) {}
   213     ///\e
   214     ///
   215     XmlIo(std::istream& _is) : _writeMode(false),
   216 			       os(std::cout), is(_is),
   217 			       line_number(1) {}
   218 
   219     ~XmlIo() { if(write()) os<< std::endl; }
   220   
   221 
   222 
   223     XmlIo &operator()(const int &v) 
   224     { 
   225       if(write()) os << v;
   226       else {
   227 	skipWhiteSpaces();
   228 	if(!(is >> const_cast<int &>(v))) 
   229 	  throw DataFormatError("",line_number,"Not an 'int'");
   230       }
   231       return *this;
   232     }
   233     XmlIo &operator()(const double &v) 
   234     {
   235       if(write()) os << v;
   236       else {
   237 	skipWhiteSpaces();
   238 	if(!(is >> const_cast<double &>(v))) 
   239 	  throw DataFormatError("",line_number,"Not an 'double'");
   240       }
   241       return *this;
   242     }
   243     XmlIo &operator()(const std::string &v)
   244     {
   245       if(write())
   246 	for(std::string::const_iterator i=v.begin();i!=v.end();++i)
   247 	  switch(*i) {
   248 	  case '\\':
   249 	    os << "\\\\";
   250 	    break;
   251 	  case '<':
   252 	    os << "\\<";
   253 	    break;
   254 	  case '&':
   255 	    os << "\\&";
   256 	    break;
   257 	  case '\n':
   258 	    os << "\\n";
   259 	    break;
   260 	  default:
   261 	    os<<*i;
   262 	    break;
   263 	  }
   264       else {
   265 	std::string &w = const_cast<std::string &>(v);
   266 	w.clear();
   267 	char c;
   268 	while (is.get(c) && c!='<')
   269 	  if(c=='\\')
   270 	    if(!is.get(c))
   271 	      throw DataFormatError("",line_number,"Bad string");
   272 	    else switch(c) {
   273 	    case 'n':
   274 	      w.push_back('\n');
   275 	      break;
   276 	    default:
   277 	      w.push_back(c);
   278 	      break;
   279 	    }
   280 	  else {
   281 	    if(c=='\n') line_number++;
   282 	    w.push_back(c);
   283 	  }
   284 	if(c!='<')
   285 	  throw DataFormatError("",line_number,"Unexpected eof");
   286 	is.unget();
   287       }
   288       return *this;
   289     }
   290 
   291 
   292     XmlIo &operator()(const std::string &_tag,const int &v) 
   293     { 
   294       LineTag t(*this,_tag);
   295       (*this)(v);
   296       return *this;
   297     }
   298     XmlIo &operator()(const std::string &_tag,const double &v) 
   299     {
   300       LineTag t(*this,_tag);
   301       (*this)(v);
   302       return *this;
   303     }
   304     XmlIo &operator()(const std::string &_tag,const std::string &v)
   305     {
   306       LineTag t(*this,_tag);
   307       (*this)(v);
   308       return *this;
   309     }
   310     ///\e
   311   
   312     ///\e
   313     ///
   314     template<class V>
   315     XmlIo &operator()(const std::string &_tag,const V &v)
   316     {
   317       Tag t(*this,_tag);
   318       xml(*this,const_cast<V &>(v));
   319       return *this;
   320     }
   321     ///\e
   322   
   323     ///\e
   324     ///
   325     template<class V>
   326     XmlIo &operator()(const V &v)
   327     {
   328       xml(*this,const_cast<V &>(v));
   329       return *this;
   330     }
   331     };
   332 
   333   //////////////////////////////////////////////////////////////////////
   334   //////////////////////////////////////////////////////////////////////
   335 
   336   ///\e
   337   
   338   ///\relates XmlIo
   339   ///
   340   template<class A>
   341   void xml(XmlIo &x,std::auto_ptr<A> &v)
   342   {
   343     if(x.write()) v=new A;
   344     x(*v);
   345   }
   346   
   347   ///\e
   348   
   349   ///\relates XmlIo
   350   ///
   351   template<class A,class B>
   352   void xml(XmlIo &x,std::pair<A,B> &v)
   353   {
   354     x("first",v.first);
   355     x("second",v.second);
   356   }
   357 
   358   ///\e
   359   
   360   ///\relates XmlIo
   361   ///
   362   template<class T>
   363   void xml(XmlIo &x,std::list<T> &v)
   364   {
   365     if(x.write())
   366       for(typename std::list<T>::const_iterator it=v.begin();
   367 	  it!=v.end();++it) x("item",*it);
   368     else while(x.nextTag()=="item")
   369       {
   370 	v.push_back(T());
   371 	x("item",v.back());
   372       }
   373   }
   374   ///\e
   375   
   376   ///\relates XmlIo
   377   ///
   378   template<class T>
   379   void xml(XmlIo &x,std::vector<T> &v)
   380   {
   381     if(x.write())
   382       for(typename std::vector<T>::const_iterator it=v.begin();
   383 	  it!=v.end();++it) x("item",*it);
   384     else while(x.nextTag()=="item")
   385       {
   386 	v.push_back(T());
   387 	x("item",v.back());      
   388       }
   389   }
   390 
   391   ///\e
   392   
   393   ///\relates XmlIo
   394   ///
   395   template<class K,class V>
   396   void xml(XmlIo &x,std::map<K,V> &v)
   397   {
   398     if(x.write()) 
   399       for(typename std::map<K,V>::const_iterator it=v.begin();
   400 	  it!=v.end();++it) x("item",*it);
   401     else while(x.nextTag()=="item")
   402       {
   403 	typename std::map<K,V>::value_type it;
   404 	x("item",it);
   405 	v.insert(it);
   406       }
   407   }
   408 
   409   ///\e
   410   
   411   ///\relates XmlIo
   412   ///
   413   template<class T>
   414   void xml(XmlIo &x,lemon::dim2::Point<T> &v)
   415   {
   416     { XmlIo::LineTag t(x,"x"); x(v.x); }
   417     { XmlIo::ContTag t(x,"y"); x(v.y); }
   418   }
   419 
   420   ///\e
   421   
   422   ///\relates XmlIo
   423   ///
   424   template<class T>
   425   void xml(XmlIo &x,lemon::dim2::BoundingBox<T> &v)
   426   {
   427     if(x.write()) {
   428       if(!v.empty()) {
   429 	x("point",v.bottomLeft());
   430 	if(v.bottomLeft()!=v.topRight()) x("point",v.topRight());
   431       }
   432     }
   433     else {
   434       v.clear();
   435       while(x.nextTag()=="point") {
   436 	lemon::dim2::Point<T> co;
   437 	x("point",co);
   438 	v.add(co);
   439       }
   440     }
   441   }
   442   
   443 }
   444