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