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