COIN-OR::LEMON - Graph Library

source: lemon-0.x/gui/xml.h @ 1737:dc821d2668c1

Last change on this file since 1737:dc821d2668c1 was 1735:41e96cd91d6d, checked in by Alpar Juttner, 18 years ago

New version of XML reader/writer.
Now, there are only a single XmlIo? class both for reading and writing.

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