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