37 level--; |
58 level--; |
38 ietag(_tag); |
59 ietag(_tag); |
39 } |
60 } |
40 |
61 |
41 public: |
62 public: |
42 |
63 ///Indent the line according to its level. |
43 void indent() |
64 |
44 { |
65 ///\warning It can only be used in write mode. |
45 if(level>=0) indent(level); |
66 /// |
46 else level=0; |
67 void indent() |
47 } |
68 { |
48 |
69 if(write()) |
49 ///\e |
70 if(level>=0) indent(level); |
50 |
71 else level=0; |
51 ///\e |
72 else throw LogicError(); |
52 /// |
73 } |
|
74 |
|
75 ///Read/write a tag |
|
76 |
|
77 ///Read/write a tag. |
|
78 ///In write mode it does not start a new line. |
53 class ContTag |
79 class ContTag |
54 { |
80 { |
55 XmlWriter &ix; |
81 XmlIo &ix; |
56 const std::string _tag; |
82 const std::string _tag; |
57 public: |
83 public: |
58 ///\e |
84 ///\e |
59 |
85 |
60 ///\e |
86 ///\e |
61 /// |
87 /// |
62 ContTag(XmlWriter &_ix,const std::string &_t) : |
88 ContTag(XmlIo &_ix,const std::string &_t) : |
63 ix(_ix), _tag(_t) |
89 ix(_ix), _tag(_t) |
64 { |
90 { |
65 ix.tag(_tag); |
91 if(ix.write()) ix.tag(_tag); |
66 } |
92 else ix.useTag(_tag); |
67 ~ContTag() { ix.etag(_tag);} |
93 } |
|
94 ~ContTag() { |
|
95 if(ix.write()) ix.etag(_tag); |
|
96 else if(!std::uncaught_exception()) ix.useTag('/'+_tag); |
|
97 } |
68 }; |
98 }; |
69 |
99 |
|
100 ///Read/write a tag |
|
101 |
|
102 ///Read/write a tag. |
|
103 ///The whole <foo> ... </foo> will be places in a single line. |
70 class LineTag |
104 class LineTag |
71 { |
105 { |
72 XmlWriter &ix; |
106 XmlIo &ix; |
73 const std::string _tag; |
107 const std::string _tag; |
74 public: |
108 public: |
75 ///\e |
109 ///\e |
76 |
110 |
77 ///\e |
111 ///\e |
78 /// |
112 /// |
79 LineTag(XmlWriter &_ix,const std::string &_t) : |
113 LineTag(XmlIo &_ix,const std::string &_t) : |
80 ix(_ix), _tag(_t) |
114 ix(_ix), _tag(_t) |
81 { |
115 { |
82 ix.itag(_tag); |
116 if(ix.write()) ix.itag(_tag); |
83 } |
117 else ix.useTag(_tag); |
84 ~LineTag() { ix.etag(_tag);} |
118 } |
|
119 ~LineTag() { |
|
120 if(ix.write()) ix.etag(_tag); |
|
121 else if(!std::uncaught_exception()) ix.useTag('/'+_tag); |
|
122 } |
85 }; |
123 }; |
86 |
124 |
87 ///\e |
125 ///Read/write a tag |
88 |
126 |
89 ///\e |
127 ///Read/write a tag. |
90 /// |
128 /// |
91 class Tag |
129 class Tag |
92 { |
130 { |
93 XmlWriter &ix; |
131 XmlIo &ix; |
94 const std::string _tag; |
132 const std::string _tag; |
95 public: |
133 public: |
96 ///\e |
134 ///\e |
97 |
135 |
98 ///\e |
136 ///\e |
99 /// |
137 /// |
100 Tag(XmlWriter &_ix,const std::string &_t) : |
138 Tag(XmlIo &_ix,const std::string &_t) : |
101 ix(_ix), _tag(_t) |
139 ix(_ix), _tag(_t) |
102 { |
140 { |
103 ix.beginTag(_tag); |
141 if(ix.write()) ix.beginTag(_tag); |
104 } |
142 else ix.useTag(_tag); |
105 ~Tag() { |
143 } |
106 ix.endTag(_tag); |
144 ~Tag() { |
|
145 if(ix.write()) ix.endTag(_tag); |
|
146 else if(!std::uncaught_exception()) ix.useTag('/'+_tag); |
107 } |
147 } |
108 }; |
148 }; |
109 |
149 |
110 ///\e |
150 private: |
111 |
151 std::istream& is; |
112 ///\e |
152 std::string next_tag; |
113 /// |
153 int line_number; |
114 XmlWriter(std::ostream& _os) : os(_os),level(-1) {} |
154 |
115 ~XmlWriter() { os<< std::endl; } |
155 void skipWhiteSpaces() |
116 |
156 { |
117 XmlWriter &operator()(int v) |
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) |
118 { |
222 { |
119 os << v; |
223 if(write()) os << v; |
120 return *this; |
224 else { |
121 } |
225 skipWhiteSpaces(); |
122 XmlWriter &operator()(const std::string &_tag,int v) |
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) |
123 { |
291 { |
124 LineTag t(*this,_tag); |
292 LineTag t(*this,_tag); |
125 (*this)(v); |
293 (*this)(v); |
126 return *this; |
294 return *this; |
127 } |
295 } |
128 XmlWriter &operator()(double v) |
296 XmlIo &operator()(const std::string &_tag,const double &v) |
129 { |
|
130 os << v; |
|
131 return *this; |
|
132 } |
|
133 XmlWriter &operator()(const std::string &_tag,double v) |
|
134 { |
297 { |
135 LineTag t(*this,_tag); |
298 LineTag t(*this,_tag); |
136 (*this)(v); |
299 (*this)(v); |
137 return *this; |
300 return *this; |
138 } |
301 } |
139 XmlWriter &operator()(const std::string &v) |
302 XmlIo &operator()(const std::string &_tag,const std::string &v) |
140 { |
|
141 for(std::string::const_iterator i=v.begin();i!=v.end();++i) |
|
142 switch(*i) { |
|
143 case '\\': |
|
144 os << "\\\\"; |
|
145 break; |
|
146 case '<': |
|
147 os << "\\<"; |
|
148 break; |
|
149 case '&': |
|
150 os << "\\&"; |
|
151 break; |
|
152 case '\n': |
|
153 os << "\\n"; |
|
154 break; |
|
155 default: |
|
156 os<<*i; |
|
157 break; |
|
158 } |
|
159 return *this; |
|
160 } |
|
161 XmlWriter &operator()(const std::string &_tag,const std::string &v) |
|
162 { |
303 { |
163 LineTag t(*this,_tag); |
304 LineTag t(*this,_tag); |
164 (*this)(v); |
305 (*this)(v); |
165 return *this; |
306 return *this; |
166 } |
307 } |
167 ///\e |
308 ///\e |
168 |
309 |
169 ///\e |
310 ///\e |
170 /// |
311 /// |
171 template<class V> |
312 template<class V> |
172 XmlWriter &operator()(const std::string &_tag,const V &v) |
313 XmlIo &operator()(const std::string &_tag,const V &v) |
173 { |
314 { |
174 Tag t(*this,_tag); |
315 Tag t(*this,_tag); |
175 out(*this,v); |
316 xml(*this,const_cast<V &>(v)); |
176 return *this; |
317 return *this; |
177 } |
318 } |
178 ///\e |
319 ///\e |
179 |
320 |
180 ///\e |
321 ///\e |
181 /// |
322 /// |
182 template<class V> |
323 template<class V> |
183 XmlWriter &operator()(const V &v) |
324 XmlIo &operator()(const V &v) |
184 { |
325 { |
185 out(*this,v); |
326 xml(*this,const_cast<V &>(v)); |
186 return *this; |
327 return *this; |
187 } |
328 } |
188 }; |
329 }; |
189 |
330 |
190 ////////////////////////////////////////////////////////////////////// |
331 ////////////////////////////////////////////////////////////////////// |
191 |
|
192 class XmlReader |
|
193 { |
|
194 std::istream& is; |
|
195 std::string next_tag; |
|
196 int line_number; |
|
197 |
|
198 void skipWhiteSpaces() |
|
199 { |
|
200 char c; |
|
201 while (is.get(c) && std::isspace(c,is.getloc())) if(c=='\n') line_number++; |
|
202 is.unget(); |
|
203 } |
|
204 protected: |
|
205 ///\e |
|
206 |
|
207 ///\e |
|
208 /// |
|
209 void useTag() {next_tag.clear();} |
|
210 |
|
211 void useTag(const std::string &_tag) { |
|
212 if(nextTag()==_tag) useTag(); |
|
213 else throw DataFormatError("",line_number,"Unexpected token name"); |
|
214 } |
|
215 public: |
|
216 ///\e |
|
217 |
|
218 ///\e |
|
219 /// |
|
220 const std::string &nextTag() |
|
221 { |
|
222 if(next_tag.empty()) { |
|
223 char c; |
|
224 skipWhiteSpaces(); |
|
225 if(!is.get(c) || c!='<') |
|
226 throw DataFormatError("",line_number,"Bad token"); |
|
227 next_tag.clear(); |
|
228 while (is.get(c) && c!='>') next_tag.push_back(c); |
|
229 if(c!='>') |
|
230 throw DataFormatError("",line_number,"Bad token"); |
|
231 } |
|
232 return next_tag; |
|
233 } |
|
234 |
|
235 ///\e |
|
236 |
|
237 ///\e |
|
238 /// |
|
239 class Tag |
|
240 { |
|
241 XmlReader &ix; |
|
242 const std::string tag; |
|
243 public: |
|
244 ///\e |
|
245 |
|
246 ///\e |
|
247 /// |
|
248 Tag(XmlReader &_ix,const std::string &_tag) : |
|
249 ix(_ix), tag(_tag) |
|
250 { |
|
251 ix.useTag(_tag); |
|
252 } |
|
253 ~Tag() { |
|
254 if(!std::uncaught_exception()) |
|
255 ix.useTag('/'+tag); |
|
256 } |
|
257 }; |
|
258 |
|
259 ///\e |
|
260 |
|
261 ///\e |
|
262 /// |
|
263 XmlReader(std::istream& _is) : is(_is), line_number(1) {} |
|
264 |
|
265 int operator()(const std::string &tag,int &v) |
|
266 { |
|
267 Tag t(*this,tag); |
|
268 skipWhiteSpaces(); |
|
269 if(!(is >> v)) throw DataFormatError("",line_number,"Not an 'int'"); |
|
270 return v; |
|
271 } |
|
272 double operator()(const std::string &tag,double &v) |
|
273 { |
|
274 Tag t(*this,tag); |
|
275 skipWhiteSpaces(); |
|
276 if(!(is >> v)) |
|
277 throw DataFormatError("",line_number,"Not a 'double'"); |
|
278 return v; |
|
279 } |
|
280 std::string &operator()(const std::string &tag,std::string &v) |
|
281 { |
|
282 Tag t(*this,tag); |
|
283 v.clear(); |
|
284 char c; |
|
285 while (is.get(c) && c!='<') |
|
286 if(c=='\\') |
|
287 if(!is.get(c)) |
|
288 throw DataFormatError("",line_number,"Bad string"); |
|
289 else switch(c) { |
|
290 case 'n': |
|
291 v.push_back('\n'); |
|
292 break; |
|
293 default: |
|
294 v.push_back(c); |
|
295 break; |
|
296 } |
|
297 else { |
|
298 if(c=='\n') line_number++; |
|
299 v.push_back(c); |
|
300 } |
|
301 if(c!='<') |
|
302 throw DataFormatError("",line_number,"Unexpected eof"); |
|
303 is.unget(); |
|
304 return v; |
|
305 } |
|
306 ///\e |
|
307 |
|
308 ///\e |
|
309 /// |
|
310 template<class V> |
|
311 V &operator()(const std::string &tag,V &v) |
|
312 { |
|
313 Tag t(*this,tag); |
|
314 in(*this,v); |
|
315 return v; |
|
316 } |
|
317 ///\e |
|
318 |
|
319 ///\e |
|
320 /// |
|
321 template<class V> |
|
322 V &operator()(V &v) |
|
323 { |
|
324 in(*this,v); |
|
325 return v; |
|
326 } |
|
327 ///\e |
|
328 |
|
329 ///\e |
|
330 /// |
|
331 template<class V> |
|
332 V load(const std::string &tag) |
|
333 { |
|
334 Tag t(*this,tag); |
|
335 V v; |
|
336 (*this)(tag,v); |
|
337 return v; |
|
338 } |
|
339 }; |
|
340 |
|
341 ////////////////////////////////////////////////////////////////////// |
332 ////////////////////////////////////////////////////////////////////// |
342 |
333 |
|
334 ///\e |
|
335 |
|
336 ///\relates XmlIo |
|
337 /// |
343 template<class A> |
338 template<class A> |
344 void out(XmlWriter &x,const std::auto_ptr<A> &v) |
339 void xml(XmlIo &x,std::auto_ptr<A> &v) |
345 { |
340 { |
|
341 if(x.write()) v=new A; |
346 x(*v); |
342 x(*v); |
347 } |
343 } |
348 |
344 |
349 template<class A> |
345 ///\e |
350 void in(XmlReader &x,std::auto_ptr<A> &v) |
346 |
351 { |
347 ///\relates XmlIo |
352 v=new A; |
348 /// |
353 x(*v); |
|
354 } |
|
355 |
|
356 ////////////////////////////// |
|
357 |
|
358 template<class A,class B> |
349 template<class A,class B> |
359 void out(XmlWriter &x,const std::pair<A,B> &v) |
350 void xml(XmlIo &x,std::pair<A,B> &v) |
360 { |
351 { |
361 x("first",v.first); |
352 x("first",v.first); |
362 x("second",v.second); |
353 x("second",v.second); |
363 } |
354 } |
364 |
355 |
365 template<class A,class B> |
356 ///\e |
366 void in(XmlReader &x,std::pair<A,B> &v) |
357 |
367 { |
358 ///\relates XmlIo |
368 x("first",v.first); |
359 /// |
369 x("second",v.second); |
|
370 } |
|
371 |
|
372 ////////////////////////////// |
|
373 |
|
374 template<class T> |
360 template<class T> |
375 void out(XmlWriter &x,const std::list<T> &v) |
361 void xml(XmlIo &x,std::list<T> &v) |
376 { |
362 { |
377 for(typename std::list<T>::const_iterator it=v.begin(); |
363 if(x.write()) |
378 it!=v.end();++it) x("item",*it); |
364 for(typename std::list<T>::const_iterator it=v.begin(); |
379 } |
365 it!=v.end();++it) x("item",*it); |
380 |
366 else while(x.nextTag()=="item") |
381 template<class T> |
|
382 void in(XmlReader &x,std::list<T> &v) |
|
383 { |
|
384 while(x.nextTag()=="item") |
|
385 { |
367 { |
386 v.push_back(T()); |
368 v.push_back(T()); |
387 x("item",v.back()); |
369 x("item",v.back()); |
388 } |
370 } |
389 } |
371 } |
390 |
372 ///\e |
391 ////////////////////////////// |
373 |
392 |
374 ///\relates XmlIo |
|
375 /// |
393 template<class T> |
376 template<class T> |
394 void out(XmlWriter &x,const std::vector<T> &v) |
377 void xml(XmlIo &x,std::vector<T> &v) |
395 { |
378 { |
396 for(typename std::vector<T>::const_iterator it=v.begin(); |
379 if(x.write()) |
397 it!=v.end();++it) x("item",*it); |
380 for(typename std::vector<T>::const_iterator it=v.begin(); |
398 } |
381 it!=v.end();++it) x("item",*it); |
399 |
382 else while(x.nextTag()=="item") |
400 template<class T> |
|
401 void in(XmlReader &x,std::vector<T> &v) |
|
402 { |
|
403 while(x.nextTag()=="item") |
|
404 { |
383 { |
405 v.push_back(T()); |
384 v.push_back(T()); |
406 x("item",v.back()); |
385 x("item",v.back()); |
407 } |
386 } |
408 } |
387 } |
409 |
388 |
410 ////////////////////////////// |
389 ///\e |
411 |
390 |
|
391 ///\relates XmlIo |
|
392 /// |
412 template<class K,class V> |
393 template<class K,class V> |
413 void out(XmlWriter &x,const std::map<K,V> &v) |
394 void xml(XmlIo &x,std::map<K,V> &v) |
414 { |
395 { |
415 for(typename std::map<K,V>::const_iterator it=v.begin(); |
396 if(x.write()) |
416 it!=v.end();++it) x("item",*it); |
397 for(typename std::map<K,V>::const_iterator it=v.begin(); |
417 } |
398 it!=v.end();++it) x("item",*it); |
418 |
399 else while(x.nextTag()=="item") |
419 template<class K,class V> |
|
420 void in(XmlReader &x,std::map<K,V> &v) |
|
421 { |
|
422 while(x.nextTag()=="item") |
|
423 { |
400 { |
424 typename std::map<K,V>::value_type it; |
401 typename std::map<K,V>::value_type it; |
425 x("item",it); |
402 x("item",it); |
426 v.insert(it); |
403 v.insert(it); |
427 } |
404 } |
428 } |
405 } |
429 |
406 |
430 ////////////////////////////// |
407 ///\e |
431 |
408 |
|
409 ///\relates XmlIo |
|
410 /// |
432 template<class T> |
411 template<class T> |
433 void out(XmlWriter &x,const lemon::xy<T> &v) |
412 void xml(XmlIo &x,lemon::xy<T> &v) |
434 { |
413 { |
435 // x("x",v.x); |
414 { XmlIo::LineTag t(x,"x"); x(v.x); } |
436 // x("y",v.y); |
415 { XmlIo::ContTag t(x,"y"); x(v.y); } |
437 { XmlWriter::LineTag t(x,"x"); x(v.x); } |
416 } |
438 { XmlWriter::ContTag t(x,"y"); x(v.y); } |
417 |
439 } |
418 ///\e |
440 |
419 |
|
420 ///\relates XmlIo |
|
421 /// |
441 template<class T> |
422 template<class T> |
442 void in(XmlReader &x,lemon::xy<T> &v) |
423 void xml(XmlIo &x,lemon::BoundingBox<T> &v) |
443 { |
424 { |
444 x("x",v.x); |
425 if(x.write()) { |
445 x("y",v.y); |
426 if(!v.empty()) { |
446 } |
427 x("point",v.bottomLeft()); |
447 |
428 if(v.bottomLeft()!=v.topRight()) x("point",v.topRight()); |
448 ////////////////////////////// |
429 } |
449 |
430 } |
450 template<class T> |
431 else { |
451 void out(XmlWriter &x,const lemon::BoundingBox<T> &v) |
432 v.clear(); |
452 { |
433 while(x.nextTag()=="point") { |
453 if(!v.empty()) { |
434 lemon::xy<T> co; |
454 x("point",v.bottomLeft()); |
435 x("point",co); |
455 if(v.bottomLeft()!=v.topRight()) x("point",v.topRight()); |
436 v.add(co); |
456 } |
437 } |
457 } |
|
458 |
|
459 template<class T> |
|
460 void in(XmlReader &x,lemon::BoundingBox<T> &v) |
|
461 { |
|
462 v.clear(); |
|
463 while(x.nextTag()=="point") { |
|
464 lemon::xy<T> co; |
|
465 x("point",co); |
|
466 v.add(co); |
|
467 } |
438 } |
468 } |
439 } |
469 |
440 |
470 } |
441 } |
|
442 |