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