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