New version of XML reader/writer.
Now, there are only a single XmlIo class both for reading and writing.
1.1 --- a/gui/xml.h Mon Oct 24 08:09:59 2005 +0000
1.2 +++ b/gui/xml.h Mon Oct 24 08:11:21 2005 +0000
1.3 @@ -1,4 +1,18 @@
1.4 -/* -*- C++ -*- */
1.5 +/* -*- C++ -*-
1.6 + * gui/xml.h - Part of LEMON, a generic C++ optimization library
1.7 + *
1.8 + * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
1.9 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
1.10 + *
1.11 + * Permission to use, modify and distribute this software is granted
1.12 + * provided that this copyright notice appears in all copies. For
1.13 + * precise terms see the accompanying LICENSE file.
1.14 + *
1.15 + * This software is provided "AS IS" with no warranty of any kind,
1.16 + * express or implied, and with no claim as to its suitability for any
1.17 + * purpose.
1.18 + *
1.19 + */
1.20
1.21 #include <iostream>
1.22 #include <string>
1.23 @@ -10,11 +24,18 @@
1.24
1.25 namespace lemon {
1.26
1.27 - class XmlWriter
1.28 + class XmlIo
1.29 {
1.30 + bool _writeMode;
1.31 + public:
1.32 + ///Check if XmlIo is in write mode.
1.33 + bool write() { return _writeMode;}
1.34 + ///Check if XmlIo is in read mode.
1.35 + bool read() { return !_writeMode;}
1.36 +
1.37 std::ostream& os;
1.38 int level;
1.39 -
1.40 +
1.41 protected:
1.42 void indent(int level) {
1.43 os << std::endl;
1.44 @@ -39,126 +60,246 @@
1.45 }
1.46
1.47 public:
1.48 + ///Indent the line according to its level.
1.49
1.50 - void indent()
1.51 + ///\warning It can only be used in write mode.
1.52 + ///
1.53 + void indent()
1.54 {
1.55 - if(level>=0) indent(level);
1.56 - else level=0;
1.57 + if(write())
1.58 + if(level>=0) indent(level);
1.59 + else level=0;
1.60 + else throw LogicError();
1.61 }
1.62
1.63 - ///\e
1.64 + ///Read/write a tag
1.65
1.66 - ///\e
1.67 - ///
1.68 + ///Read/write a tag.
1.69 + ///In write mode it does not start a new line.
1.70 class ContTag
1.71 {
1.72 - XmlWriter &ix;
1.73 + XmlIo &ix;
1.74 const std::string _tag;
1.75 public:
1.76 ///\e
1.77
1.78 ///\e
1.79 ///
1.80 - ContTag(XmlWriter &_ix,const std::string &_t) :
1.81 + ContTag(XmlIo &_ix,const std::string &_t) :
1.82 ix(_ix), _tag(_t)
1.83 {
1.84 - ix.tag(_tag);
1.85 + if(ix.write()) ix.tag(_tag);
1.86 + else ix.useTag(_tag);
1.87 }
1.88 - ~ContTag() { ix.etag(_tag);}
1.89 + ~ContTag() {
1.90 + if(ix.write()) ix.etag(_tag);
1.91 + else if(!std::uncaught_exception()) ix.useTag('/'+_tag);
1.92 + }
1.93 };
1.94
1.95 + ///Read/write a tag
1.96 +
1.97 + ///Read/write a tag.
1.98 + ///The whole <foo> ... </foo> will be places in a single line.
1.99 class LineTag
1.100 {
1.101 - XmlWriter &ix;
1.102 + XmlIo &ix;
1.103 const std::string _tag;
1.104 public:
1.105 ///\e
1.106
1.107 ///\e
1.108 ///
1.109 - LineTag(XmlWriter &_ix,const std::string &_t) :
1.110 + LineTag(XmlIo &_ix,const std::string &_t) :
1.111 ix(_ix), _tag(_t)
1.112 {
1.113 - ix.itag(_tag);
1.114 + if(ix.write()) ix.itag(_tag);
1.115 + else ix.useTag(_tag);
1.116 }
1.117 - ~LineTag() { ix.etag(_tag);}
1.118 + ~LineTag() {
1.119 + if(ix.write()) ix.etag(_tag);
1.120 + else if(!std::uncaught_exception()) ix.useTag('/'+_tag);
1.121 + }
1.122 };
1.123
1.124 - ///\e
1.125 + ///Read/write a tag
1.126
1.127 - ///\e
1.128 + ///Read/write a tag.
1.129 ///
1.130 class Tag
1.131 {
1.132 - XmlWriter &ix;
1.133 + XmlIo &ix;
1.134 const std::string _tag;
1.135 public:
1.136 ///\e
1.137
1.138 ///\e
1.139 ///
1.140 - Tag(XmlWriter &_ix,const std::string &_t) :
1.141 + Tag(XmlIo &_ix,const std::string &_t) :
1.142 ix(_ix), _tag(_t)
1.143 {
1.144 - ix.beginTag(_tag);
1.145 + if(ix.write()) ix.beginTag(_tag);
1.146 + else ix.useTag(_tag);
1.147 }
1.148 - ~Tag() {
1.149 - ix.endTag(_tag);
1.150 + ~Tag() {
1.151 + if(ix.write()) ix.endTag(_tag);
1.152 + else if(!std::uncaught_exception()) ix.useTag('/'+_tag);
1.153 }
1.154 };
1.155 -
1.156 +
1.157 + private:
1.158 + std::istream& is;
1.159 + std::string next_tag;
1.160 + int line_number;
1.161 +
1.162 + void skipWhiteSpaces()
1.163 + {
1.164 + if(write()) throw LogicError();
1.165 + {
1.166 + char c;
1.167 + while (is.get(c) && std::isspace(c,is.getloc()))
1.168 + if(c=='\n') line_number++;
1.169 + is.unget();
1.170 + }
1.171 + }
1.172 + protected:
1.173 + /// Use the next tag.
1.174 +
1.175 + ///\e
1.176 + ///
1.177 + void useTag() {next_tag.clear();}
1.178 +
1.179 + ///Use the next tag and check if it is equal with \c _tag
1.180 +
1.181 + ///\e
1.182 + ///
1.183 + void useTag(const std::string &_tag) {
1.184 + if(nextTag()==_tag) useTag();
1.185 + else throw DataFormatError("",line_number,"Unexpected token name");
1.186 + }
1.187 + public:
1.188 + ///Return the next tag (if a tag follows on the stream).
1.189 +
1.190 + ///\warning It can only be used in read mode.
1.191 + ///
1.192 + const std::string &nextTag()
1.193 + {
1.194 + if(write()) throw LogicError();
1.195 + else if(next_tag.empty()) {
1.196 + char c;
1.197 + skipWhiteSpaces();
1.198 + if(!is.get(c) || c!='<')
1.199 + throw DataFormatError("",line_number,"Bad format");
1.200 + next_tag.clear();
1.201 + while (is.get(c) && c!='>') next_tag.push_back(c);
1.202 + if(c!='>')
1.203 + throw DataFormatError("",line_number,"Bad format");
1.204 + }
1.205 + return next_tag;
1.206 + }
1.207 +
1.208 + /**********************************************************************/
1.209 +
1.210 +
1.211 ///\e
1.212
1.213 ///\e
1.214 ///
1.215 - XmlWriter(std::ostream& _os) : os(_os),level(-1) {}
1.216 - ~XmlWriter() { os<< std::endl; }
1.217 + XmlIo(std::ostream& _os) : _writeMode(true), os(_os),
1.218 + level(-1),
1.219 + is(*(std::istream*)(NULL)) {}
1.220 + ///\e
1.221 + ///
1.222 + XmlIo(std::istream& _is) : _writeMode(false),
1.223 + os(*(std::ostream*)(NULL)), is(_is),
1.224 + line_number(1) {}
1.225 +
1.226 + ~XmlIo() { if(write()) os<< std::endl; }
1.227
1.228 - XmlWriter &operator()(int v)
1.229 +
1.230 +
1.231 + XmlIo &operator()(const int &v)
1.232 {
1.233 - os << v;
1.234 + if(write()) os << v;
1.235 + else {
1.236 + skipWhiteSpaces();
1.237 + if(!(is >> const_cast<int &>(v)))
1.238 + throw DataFormatError("",line_number,"Not an 'int'");
1.239 + }
1.240 return *this;
1.241 }
1.242 - XmlWriter &operator()(const std::string &_tag,int v)
1.243 + XmlIo &operator()(const double &v)
1.244 + {
1.245 + if(write()) os << v;
1.246 + else {
1.247 + skipWhiteSpaces();
1.248 + if(!(is >> const_cast<double &>(v)))
1.249 + throw DataFormatError("",line_number,"Not an 'double'");
1.250 + }
1.251 + return *this;
1.252 + }
1.253 + XmlIo &operator()(const std::string &v)
1.254 + {
1.255 + if(write())
1.256 + for(std::string::const_iterator i=v.begin();i!=v.end();++i)
1.257 + switch(*i) {
1.258 + case '\\':
1.259 + os << "\\\\";
1.260 + break;
1.261 + case '<':
1.262 + os << "\\<";
1.263 + break;
1.264 + case '&':
1.265 + os << "\\&";
1.266 + break;
1.267 + case '\n':
1.268 + os << "\\n";
1.269 + break;
1.270 + default:
1.271 + os<<*i;
1.272 + break;
1.273 + }
1.274 + else {
1.275 + std::string &w = const_cast<std::string &>(v);
1.276 + w.clear();
1.277 + char c;
1.278 + while (is.get(c) && c!='<')
1.279 + if(c=='\\')
1.280 + if(!is.get(c))
1.281 + throw DataFormatError("",line_number,"Bad string");
1.282 + else switch(c) {
1.283 + case 'n':
1.284 + w.push_back('\n');
1.285 + break;
1.286 + default:
1.287 + w.push_back(c);
1.288 + break;
1.289 + }
1.290 + else {
1.291 + if(c=='\n') line_number++;
1.292 + w.push_back(c);
1.293 + }
1.294 + if(c!='<')
1.295 + throw DataFormatError("",line_number,"Unexpected eof");
1.296 + is.unget();
1.297 + }
1.298 + return *this;
1.299 + }
1.300 +
1.301 +
1.302 + XmlIo &operator()(const std::string &_tag,const int &v)
1.303 {
1.304 LineTag t(*this,_tag);
1.305 (*this)(v);
1.306 return *this;
1.307 }
1.308 - XmlWriter &operator()(double v)
1.309 - {
1.310 - os << v;
1.311 - return *this;
1.312 - }
1.313 - XmlWriter &operator()(const std::string &_tag,double v)
1.314 + XmlIo &operator()(const std::string &_tag,const double &v)
1.315 {
1.316 LineTag t(*this,_tag);
1.317 (*this)(v);
1.318 return *this;
1.319 }
1.320 - XmlWriter &operator()(const std::string &v)
1.321 - {
1.322 - for(std::string::const_iterator i=v.begin();i!=v.end();++i)
1.323 - switch(*i) {
1.324 - case '\\':
1.325 - os << "\\\\";
1.326 - break;
1.327 - case '<':
1.328 - os << "\\<";
1.329 - break;
1.330 - case '&':
1.331 - os << "\\&";
1.332 - break;
1.333 - case '\n':
1.334 - os << "\\n";
1.335 - break;
1.336 - default:
1.337 - os<<*i;
1.338 - break;
1.339 - }
1.340 - return *this;
1.341 - }
1.342 - XmlWriter &operator()(const std::string &_tag,const std::string &v)
1.343 + XmlIo &operator()(const std::string &_tag,const std::string &v)
1.344 {
1.345 LineTag t(*this,_tag);
1.346 (*this)(v);
1.347 @@ -169,10 +310,10 @@
1.348 ///\e
1.349 ///
1.350 template<class V>
1.351 - XmlWriter &operator()(const std::string &_tag,const V &v)
1.352 + XmlIo &operator()(const std::string &_tag,const V &v)
1.353 {
1.354 Tag t(*this,_tag);
1.355 - out(*this,v);
1.356 + xml(*this,const_cast<V &>(v));
1.357 return *this;
1.358 }
1.359 ///\e
1.360 @@ -180,246 +321,82 @@
1.361 ///\e
1.362 ///
1.363 template<class V>
1.364 - XmlWriter &operator()(const V &v)
1.365 + XmlIo &operator()(const V &v)
1.366 {
1.367 - out(*this,v);
1.368 + xml(*this,const_cast<V &>(v));
1.369 return *this;
1.370 }
1.371 - };
1.372 + };
1.373
1.374 //////////////////////////////////////////////////////////////////////
1.375 -
1.376 - class XmlReader
1.377 - {
1.378 - std::istream& is;
1.379 - std::string next_tag;
1.380 - int line_number;
1.381 -
1.382 - void skipWhiteSpaces()
1.383 - {
1.384 - char c;
1.385 - while (is.get(c) && std::isspace(c,is.getloc())) if(c=='\n') line_number++;
1.386 - is.unget();
1.387 - }
1.388 - protected:
1.389 - ///\e
1.390 -
1.391 - ///\e
1.392 - ///
1.393 - void useTag() {next_tag.clear();}
1.394 -
1.395 - void useTag(const std::string &_tag) {
1.396 - if(nextTag()==_tag) useTag();
1.397 - else throw DataFormatError("",line_number,"Unexpected token name");
1.398 - }
1.399 - public:
1.400 - ///\e
1.401 -
1.402 - ///\e
1.403 - ///
1.404 - const std::string &nextTag()
1.405 - {
1.406 - if(next_tag.empty()) {
1.407 - char c;
1.408 - skipWhiteSpaces();
1.409 - if(!is.get(c) || c!='<')
1.410 - throw DataFormatError("",line_number,"Bad token");
1.411 - next_tag.clear();
1.412 - while (is.get(c) && c!='>') next_tag.push_back(c);
1.413 - if(c!='>')
1.414 - throw DataFormatError("",line_number,"Bad token");
1.415 - }
1.416 - return next_tag;
1.417 - }
1.418 -
1.419 - ///\e
1.420 -
1.421 - ///\e
1.422 - ///
1.423 - class Tag
1.424 - {
1.425 - XmlReader &ix;
1.426 - const std::string tag;
1.427 - public:
1.428 - ///\e
1.429 -
1.430 - ///\e
1.431 - ///
1.432 - Tag(XmlReader &_ix,const std::string &_tag) :
1.433 - ix(_ix), tag(_tag)
1.434 - {
1.435 - ix.useTag(_tag);
1.436 - }
1.437 - ~Tag() {
1.438 - if(!std::uncaught_exception())
1.439 - ix.useTag('/'+tag);
1.440 - }
1.441 - };
1.442 -
1.443 - ///\e
1.444 -
1.445 - ///\e
1.446 - ///
1.447 - XmlReader(std::istream& _is) : is(_is), line_number(1) {}
1.448 -
1.449 - int operator()(const std::string &tag,int &v)
1.450 - {
1.451 - Tag t(*this,tag);
1.452 - skipWhiteSpaces();
1.453 - if(!(is >> v)) throw DataFormatError("",line_number,"Not an 'int'");
1.454 - return v;
1.455 - }
1.456 - double operator()(const std::string &tag,double &v)
1.457 - {
1.458 - Tag t(*this,tag);
1.459 - skipWhiteSpaces();
1.460 - if(!(is >> v))
1.461 - throw DataFormatError("",line_number,"Not a 'double'");
1.462 - return v;
1.463 - }
1.464 - std::string &operator()(const std::string &tag,std::string &v)
1.465 - {
1.466 - Tag t(*this,tag);
1.467 - v.clear();
1.468 - char c;
1.469 - while (is.get(c) && c!='<')
1.470 - if(c=='\\')
1.471 - if(!is.get(c))
1.472 - throw DataFormatError("",line_number,"Bad string");
1.473 - else switch(c) {
1.474 - case 'n':
1.475 - v.push_back('\n');
1.476 - break;
1.477 - default:
1.478 - v.push_back(c);
1.479 - break;
1.480 - }
1.481 - else {
1.482 - if(c=='\n') line_number++;
1.483 - v.push_back(c);
1.484 - }
1.485 - if(c!='<')
1.486 - throw DataFormatError("",line_number,"Unexpected eof");
1.487 - is.unget();
1.488 - return v;
1.489 - }
1.490 - ///\e
1.491 -
1.492 - ///\e
1.493 - ///
1.494 - template<class V>
1.495 - V &operator()(const std::string &tag,V &v)
1.496 - {
1.497 - Tag t(*this,tag);
1.498 - in(*this,v);
1.499 - return v;
1.500 - }
1.501 - ///\e
1.502 -
1.503 - ///\e
1.504 - ///
1.505 - template<class V>
1.506 - V &operator()(V &v)
1.507 - {
1.508 - in(*this,v);
1.509 - return v;
1.510 - }
1.511 - ///\e
1.512 -
1.513 - ///\e
1.514 - ///
1.515 - template<class V>
1.516 - V load(const std::string &tag)
1.517 - {
1.518 - Tag t(*this,tag);
1.519 - V v;
1.520 - (*this)(tag,v);
1.521 - return v;
1.522 - }
1.523 - };
1.524 -
1.525 //////////////////////////////////////////////////////////////////////
1.526
1.527 + ///\e
1.528 +
1.529 + ///\relates XmlIo
1.530 + ///
1.531 template<class A>
1.532 - void out(XmlWriter &x,const std::auto_ptr<A> &v)
1.533 + void xml(XmlIo &x,std::auto_ptr<A> &v)
1.534 {
1.535 + if(x.write()) v=new A;
1.536 x(*v);
1.537 }
1.538 -
1.539 - template<class A>
1.540 - void in(XmlReader &x,std::auto_ptr<A> &v)
1.541 - {
1.542 - v=new A;
1.543 - x(*v);
1.544 - }
1.545 -
1.546 - //////////////////////////////
1.547 -
1.548 +
1.549 + ///\e
1.550 +
1.551 + ///\relates XmlIo
1.552 + ///
1.553 template<class A,class B>
1.554 - void out(XmlWriter &x,const std::pair<A,B> &v)
1.555 + void xml(XmlIo &x,std::pair<A,B> &v)
1.556 {
1.557 x("first",v.first);
1.558 x("second",v.second);
1.559 }
1.560
1.561 - template<class A,class B>
1.562 - void in(XmlReader &x,std::pair<A,B> &v)
1.563 + ///\e
1.564 +
1.565 + ///\relates XmlIo
1.566 + ///
1.567 + template<class T>
1.568 + void xml(XmlIo &x,std::list<T> &v)
1.569 {
1.570 - x("first",v.first);
1.571 - x("second",v.second);
1.572 - }
1.573 -
1.574 - //////////////////////////////
1.575 -
1.576 - template<class T>
1.577 - void out(XmlWriter &x,const std::list<T> &v)
1.578 - {
1.579 - for(typename std::list<T>::const_iterator it=v.begin();
1.580 - it!=v.end();++it) x("item",*it);
1.581 - }
1.582 -
1.583 - template<class T>
1.584 - void in(XmlReader &x,std::list<T> &v)
1.585 - {
1.586 - while(x.nextTag()=="item")
1.587 + if(x.write())
1.588 + for(typename std::list<T>::const_iterator it=v.begin();
1.589 + it!=v.end();++it) x("item",*it);
1.590 + else while(x.nextTag()=="item")
1.591 {
1.592 v.push_back(T());
1.593 x("item",v.back());
1.594 }
1.595 }
1.596 -
1.597 - //////////////////////////////
1.598 -
1.599 + ///\e
1.600 +
1.601 + ///\relates XmlIo
1.602 + ///
1.603 template<class T>
1.604 - void out(XmlWriter &x,const std::vector<T> &v)
1.605 + void xml(XmlIo &x,std::vector<T> &v)
1.606 {
1.607 - for(typename std::vector<T>::const_iterator it=v.begin();
1.608 - it!=v.end();++it) x("item",*it);
1.609 - }
1.610 -
1.611 - template<class T>
1.612 - void in(XmlReader &x,std::vector<T> &v)
1.613 - {
1.614 - while(x.nextTag()=="item")
1.615 + if(x.write())
1.616 + for(typename std::vector<T>::const_iterator it=v.begin();
1.617 + it!=v.end();++it) x("item",*it);
1.618 + else while(x.nextTag()=="item")
1.619 {
1.620 v.push_back(T());
1.621 x("item",v.back());
1.622 }
1.623 }
1.624
1.625 - //////////////////////////////
1.626 -
1.627 + ///\e
1.628 +
1.629 + ///\relates XmlIo
1.630 + ///
1.631 template<class K,class V>
1.632 - void out(XmlWriter &x,const std::map<K,V> &v)
1.633 + void xml(XmlIo &x,std::map<K,V> &v)
1.634 {
1.635 - for(typename std::map<K,V>::const_iterator it=v.begin();
1.636 - it!=v.end();++it) x("item",*it);
1.637 - }
1.638 -
1.639 - template<class K,class V>
1.640 - void in(XmlReader &x,std::map<K,V> &v)
1.641 - {
1.642 - while(x.nextTag()=="item")
1.643 + if(x.write())
1.644 + for(typename std::map<K,V>::const_iterator it=v.begin();
1.645 + it!=v.end();++it) x("item",*it);
1.646 + else while(x.nextTag()=="item")
1.647 {
1.648 typename std::map<K,V>::value_type it;
1.649 x("item",it);
1.650 @@ -427,44 +404,39 @@
1.651 }
1.652 }
1.653
1.654 - //////////////////////////////
1.655 -
1.656 + ///\e
1.657 +
1.658 + ///\relates XmlIo
1.659 + ///
1.660 template<class T>
1.661 - void out(XmlWriter &x,const lemon::xy<T> &v)
1.662 + void xml(XmlIo &x,lemon::xy<T> &v)
1.663 {
1.664 - // x("x",v.x);
1.665 - // x("y",v.y);
1.666 - { XmlWriter::LineTag t(x,"x"); x(v.x); }
1.667 - { XmlWriter::ContTag t(x,"y"); x(v.y); }
1.668 + { XmlIo::LineTag t(x,"x"); x(v.x); }
1.669 + { XmlIo::ContTag t(x,"y"); x(v.y); }
1.670 }
1.671
1.672 + ///\e
1.673 +
1.674 + ///\relates XmlIo
1.675 + ///
1.676 template<class T>
1.677 - void in(XmlReader &x,lemon::xy<T> &v)
1.678 + void xml(XmlIo &x,lemon::BoundingBox<T> &v)
1.679 {
1.680 - x("x",v.x);
1.681 - x("y",v.y);
1.682 - }
1.683 -
1.684 - //////////////////////////////
1.685 -
1.686 - template<class T>
1.687 - void out(XmlWriter &x,const lemon::BoundingBox<T> &v)
1.688 - {
1.689 - if(!v.empty()) {
1.690 - x("point",v.bottomLeft());
1.691 - if(v.bottomLeft()!=v.topRight()) x("point",v.topRight());
1.692 + if(x.write()) {
1.693 + if(!v.empty()) {
1.694 + x("point",v.bottomLeft());
1.695 + if(v.bottomLeft()!=v.topRight()) x("point",v.topRight());
1.696 + }
1.697 }
1.698 - }
1.699 -
1.700 - template<class T>
1.701 - void in(XmlReader &x,lemon::BoundingBox<T> &v)
1.702 - {
1.703 - v.clear();
1.704 - while(x.nextTag()=="point") {
1.705 - lemon::xy<T> co;
1.706 - x("point",co);
1.707 - v.add(co);
1.708 + else {
1.709 + v.clear();
1.710 + while(x.nextTag()=="point") {
1.711 + lemon::xy<T> co;
1.712 + x("point",co);
1.713 + v.add(co);
1.714 + }
1.715 }
1.716 }
1.717
1.718 }
1.719 +