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