xml.h
author alpar
Tue, 31 Jan 2006 21:14:11 +0000
branchgui
changeset 127 656ac25e009b
parent 124 b8d778d4d100
child 150 86273bfe0e4d
permissions -rw-r--r--
Fix icc compilation failures.
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@124
   103
    ///The whole \<foo\> ... \</foo\> will be placed 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@127
   210
			       is(std::cin) {}
alpar@83
   211
    ///\e
alpar@83
   212
    ///
alpar@83
   213
    XmlIo(std::istream& _is) : _writeMode(false),
alpar@127
   214
			       os(std::cout), 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