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