xml.h
author ladanyi
Tue, 23 Aug 2005 16:27:59 +0000
branchgui
changeset 65 1b8e20c04704
parent 2 358b707800b8
child 83 6c0db51a1d99
permissions -rw-r--r--
bugfix
     1 /* -*- C++ -*- */
     2 
     3 #include <iostream>
     4 #include <string>
     5 #include <vector>
     6 #include <list>
     7 #include <map>
     8 #include <lemon/error.h>
     9 #include <lemon/xy.h>
    10 
    11 namespace lemon {
    12 
    13   class XmlWriter 
    14   {
    15     std::ostream& os;
    16     int level;
    17 
    18   protected:
    19     void indent(int level) {
    20       os << std::endl;
    21       for(int i=0;i<level;i++) os << ' ';
    22     }
    23     void tag(const std::string &_tag) {
    24       os << '<' << _tag << '>';
    25     }
    26     void etag(const std::string &_tag) {
    27       os << "</" << _tag << '>';
    28     }
    29     void itag(const std::string &_tag) { indent();tag(_tag); }
    30     void ietag(const std::string &_tag) { indent();etag(_tag); }
    31 
    32     void beginTag(const std::string &_tag) {
    33       itag(_tag);
    34       level++;
    35     }
    36     void endTag(const std::string &_tag) {
    37       level--;
    38       ietag(_tag);
    39     }
    40 
    41   public:
    42 
    43     void indent() 
    44     {
    45       if(level>=0) indent(level);
    46       else level=0;
    47     }
    48   
    49     ///\e
    50   
    51     ///\e
    52     ///
    53     class ContTag
    54     {
    55       XmlWriter &ix;
    56       const std::string _tag;
    57     public:
    58       ///\e
    59   
    60       ///\e
    61       ///
    62       ContTag(XmlWriter &_ix,const std::string &_t) :
    63 	ix(_ix), _tag(_t)
    64       {
    65 	ix.tag(_tag);
    66       }
    67       ~ContTag() { ix.etag(_tag);}
    68     };
    69 
    70     class LineTag
    71     {
    72       XmlWriter &ix;
    73       const std::string _tag;
    74     public:
    75       ///\e
    76     
    77       ///\e
    78       ///
    79       LineTag(XmlWriter &_ix,const std::string &_t) :
    80 	ix(_ix), _tag(_t)
    81       {
    82 	ix.itag(_tag);
    83       }
    84       ~LineTag() { ix.etag(_tag);}
    85     };
    86 
    87     ///\e
    88   
    89     ///\e
    90     ///
    91     class Tag
    92     {
    93       XmlWriter &ix;
    94       const std::string _tag;
    95     public:
    96       ///\e
    97   
    98       ///\e
    99       ///
   100       Tag(XmlWriter &_ix,const std::string &_t) :
   101 	ix(_ix), _tag(_t)
   102       {
   103 	ix.beginTag(_tag);
   104       }
   105       ~Tag() { 
   106 	ix.endTag(_tag);
   107       }
   108     };
   109       
   110     ///\e
   111   
   112     ///\e
   113     ///
   114     XmlWriter(std::ostream& _os) : os(_os),level(-1) {}
   115     ~XmlWriter() { os<< std::endl; }
   116   
   117     XmlWriter &operator()(int v) 
   118     { 
   119       os << v;
   120       return *this;
   121     }
   122     XmlWriter &operator()(const std::string &_tag,int v) 
   123     { 
   124       LineTag t(*this,_tag);
   125       (*this)(v);
   126       return *this;
   127     }
   128     XmlWriter &operator()(double v) 
   129     {
   130       os << v;
   131       return *this;
   132     }
   133     XmlWriter &operator()(const std::string &_tag,double v) 
   134     {
   135       LineTag t(*this,_tag);
   136       (*this)(v);
   137       return *this;
   138     }
   139     XmlWriter &operator()(const std::string &v)
   140     {
   141       for(std::string::const_iterator i=v.begin();i!=v.end();++i)
   142 	switch(*i) {
   143 	case '\\':
   144 	  os << "\\\\";
   145 	  break;
   146 	case '<':
   147 	  os << "\\<";
   148 	  break;
   149 	case '&':
   150 	  os << "\\&";
   151 	  break;
   152 	case '\n':
   153 	  os << "\\n";
   154 	  break;
   155 	default:
   156 	  os<<*i;
   157 	  break;
   158 	}
   159       return *this;
   160     }
   161     XmlWriter &operator()(const std::string &_tag,const std::string &v)
   162     {
   163       LineTag t(*this,_tag);
   164       (*this)(v);
   165       return *this;
   166     }
   167     ///\e
   168   
   169     ///\e
   170     ///
   171     template<class V>
   172     XmlWriter &operator()(const std::string &_tag,const V &v)
   173     {
   174       Tag t(*this,_tag);
   175       out(*this,v);
   176       return *this;
   177     }
   178     ///\e
   179   
   180     ///\e
   181     ///
   182     template<class V>
   183     XmlWriter &operator()(const V &v)
   184     {
   185       out(*this,v);
   186       return *this;
   187     }
   188   };
   189 
   190   //////////////////////////////////////////////////////////////////////
   191 
   192   class XmlReader 
   193   {
   194     std::istream& is;
   195     std::string next_tag;
   196     int line_number;
   197 
   198     void skipWhiteSpaces()
   199     {
   200       char c;
   201       while (is.get(c) && std::isspace(c,is.getloc())) if(c=='\n') line_number++;
   202       is.unget();
   203     }
   204   protected:
   205     ///\e
   206   
   207     ///\e
   208     ///
   209     void useTag() {next_tag.clear();}
   210   
   211     void useTag(const std::string &_tag) {
   212       if(nextTag()==_tag) useTag();
   213       else throw DataFormatError("",line_number,"Unexpected token name");
   214     }
   215   public:
   216     ///\e
   217   
   218     ///\e
   219     ///
   220     const std::string &nextTag() 
   221     {
   222       if(next_tag.empty()) {
   223 	char c;
   224 	skipWhiteSpaces();
   225 	if(!is.get(c) || c!='<')
   226 	  throw DataFormatError("",line_number,"Bad token");
   227 	next_tag.clear();
   228 	while (is.get(c) && c!='>') next_tag.push_back(c);
   229 	if(c!='>')
   230 	  throw DataFormatError("",line_number,"Bad token");
   231       }
   232       return next_tag;
   233     }
   234   
   235     ///\e
   236   
   237     ///\e
   238     ///
   239     class Tag
   240     {
   241       XmlReader &ix;
   242       const std::string tag;
   243     public:
   244       ///\e
   245     
   246       ///\e
   247       ///
   248       Tag(XmlReader &_ix,const std::string &_tag) :
   249 	ix(_ix), tag(_tag)
   250       {
   251 	ix.useTag(_tag);
   252       }
   253       ~Tag() {
   254 	if(!std::uncaught_exception()) 
   255 	  ix.useTag('/'+tag);
   256       }
   257     };
   258 
   259     ///\e
   260   
   261     ///\e
   262     ///
   263     XmlReader(std::istream& _is) : is(_is), line_number(1) {}
   264   
   265     int operator()(const std::string &tag,int &v)
   266     { 
   267       Tag t(*this,tag);
   268       skipWhiteSpaces();
   269       if(!(is >> v)) throw DataFormatError("",line_number,"Not an 'int'");
   270       return v;
   271     }
   272     double operator()(const std::string &tag,double &v) 
   273     {
   274       Tag t(*this,tag);
   275       skipWhiteSpaces();
   276       if(!(is >> v))
   277 	throw DataFormatError("",line_number,"Not a 'double'");
   278       return v;
   279     }
   280     std::string &operator()(const std::string &tag,std::string &v)
   281     {
   282       Tag t(*this,tag);
   283       v.clear();
   284       char c;
   285       while (is.get(c) && c!='<')
   286 	if(c=='\\')
   287 	  if(!is.get(c))
   288 	    throw DataFormatError("",line_number,"Bad string");
   289 	  else switch(c) {
   290 	  case 'n':
   291 	    v.push_back('\n');
   292 	    break;
   293 	  default:
   294 	    v.push_back(c);
   295 	    break;
   296 	  }
   297 	else {
   298 	  if(c=='\n') line_number++;
   299 	  v.push_back(c);
   300 	}
   301       if(c!='<')
   302 	throw DataFormatError("",line_number,"Unexpected eof");
   303       is.unget();
   304       return v;
   305     }
   306     ///\e
   307   
   308     ///\e
   309     ///
   310     template<class V>
   311     V &operator()(const std::string &tag,V &v)
   312     {
   313       Tag t(*this,tag);
   314       in(*this,v);
   315       return v;
   316     }
   317     ///\e
   318   
   319     ///\e
   320     ///
   321     template<class V>
   322     V &operator()(V &v)
   323     {
   324       in(*this,v);
   325       return v;
   326     }
   327     ///\e
   328   
   329     ///\e
   330     ///
   331     template<class V>
   332     V load(const std::string &tag)
   333     {
   334       Tag t(*this,tag);
   335       V v;
   336       (*this)(tag,v);
   337       return v;
   338     }
   339   };
   340 
   341   //////////////////////////////////////////////////////////////////////
   342 
   343   template<class A>
   344   void out(XmlWriter &x,const std::auto_ptr<A> &v)
   345   {
   346     x(*v);
   347   }
   348 
   349   template<class A>
   350   void in(XmlReader &x,std::auto_ptr<A> &v)
   351   {
   352     v=new A;
   353     x(*v);
   354   }
   355 
   356   //////////////////////////////
   357 
   358   template<class A,class B>
   359   void out(XmlWriter &x,const std::pair<A,B> &v)
   360   {
   361     x("first",v.first);
   362     x("second",v.second);
   363   }
   364 
   365   template<class A,class B>
   366   void in(XmlReader &x,std::pair<A,B> &v)
   367   {
   368     x("first",v.first);
   369     x("second",v.second);
   370   }
   371 
   372   //////////////////////////////
   373 
   374   template<class T>
   375   void out(XmlWriter &x,const std::list<T> &v)
   376   {
   377     for(typename std::list<T>::const_iterator it=v.begin();
   378 	it!=v.end();++it) x("item",*it);
   379   }
   380 
   381   template<class T>
   382   void in(XmlReader &x,std::list<T> &v)
   383   {
   384     while(x.nextTag()=="item")
   385       {
   386 	v.push_back(T());
   387 	x("item",v.back());
   388       }
   389   }
   390 
   391   //////////////////////////////
   392 
   393   template<class T>
   394   void out(XmlWriter &x,const std::vector<T> &v)
   395   {
   396     for(typename std::vector<T>::const_iterator it=v.begin();
   397 	it!=v.end();++it) x("item",*it);
   398   }
   399 
   400   template<class T>
   401   void in(XmlReader &x,std::vector<T> &v)
   402   {
   403     while(x.nextTag()=="item")
   404       {
   405 	v.push_back(T());
   406 	x("item",v.back());      
   407       }
   408   }
   409 
   410   //////////////////////////////
   411 
   412   template<class K,class V>
   413   void out(XmlWriter &x,const std::map<K,V> &v)
   414   {
   415     for(typename std::map<K,V>::const_iterator it=v.begin();
   416 	it!=v.end();++it) x("item",*it);
   417   }
   418 
   419   template<class K,class V>
   420   void in(XmlReader &x,std::map<K,V> &v)
   421   {
   422     while(x.nextTag()=="item")
   423       {
   424 	typename std::map<K,V>::value_type it;
   425 	x("item",it);
   426 	v.insert(it);
   427       }
   428   }
   429 
   430   //////////////////////////////
   431 
   432   template<class T>
   433   void out(XmlWriter &x,const lemon::xy<T> &v)
   434   {
   435     //   x("x",v.x);
   436     //   x("y",v.y);
   437     { XmlWriter::LineTag t(x,"x"); x(v.x); }
   438     { XmlWriter::ContTag t(x,"y"); x(v.y); }
   439   }
   440 
   441   template<class T>
   442   void in(XmlReader &x,lemon::xy<T> &v)
   443   {
   444     x("x",v.x);
   445     x("y",v.y);
   446   }
   447 
   448   //////////////////////////////
   449 
   450   template<class T>
   451   void out(XmlWriter &x,const lemon::BoundingBox<T> &v)
   452   {
   453     if(!v.empty()) {
   454       x("point",v.bottomLeft());
   455       if(v.bottomLeft()!=v.topRight()) x("point",v.topRight());
   456     }
   457   }
   458 
   459   template<class T>
   460   void in(XmlReader &x,lemon::BoundingBox<T> &v)
   461   {
   462     v.clear();
   463     while(x.nextTag()=="point") {
   464       lemon::xy<T> co;
   465       x("point",co);
   466       v.add(co);
   467     }
   468   }
   469   
   470 }