1 | /*=============================================================================
|
---|
2 | Copyright (c) 2001-2003 Hartmut Kaiser
|
---|
3 | Copyright (c) 2001-2003 Daniel Nuffer
|
---|
4 | http://spirit.sourceforge.net/
|
---|
5 |
|
---|
6 | Use, modification and distribution is subject to the Boost Software
|
---|
7 | License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
---|
8 | http://www.boost.org/LICENSE_1_0.txt)
|
---|
9 | =============================================================================*/
|
---|
10 |
|
---|
11 | #if !defined(TREE_TO_XML_IPP)
|
---|
12 | #define TREE_TO_XML_IPP
|
---|
13 |
|
---|
14 | #include <cstdio>
|
---|
15 | #include <cstdarg>
|
---|
16 |
|
---|
17 | #include <map>
|
---|
18 | #include <iostream>
|
---|
19 | #include <boost/config.hpp>
|
---|
20 | #ifdef BOOST_NO_STRINGSTREAM
|
---|
21 | #include <strstream>
|
---|
22 | #define BOOST_SPIRIT_OSSTREAM std::ostrstream
|
---|
23 | inline std::string BOOST_SPIRIT_GETSTRING(std::ostrstream& ss)
|
---|
24 | {
|
---|
25 | ss << ends;
|
---|
26 | std::string rval = ss.str();
|
---|
27 | ss.freeze(false);
|
---|
28 | return rval;
|
---|
29 | }
|
---|
30 | #else
|
---|
31 | #include <sstream>
|
---|
32 | #define BOOST_SPIRIT_GETSTRING(ss) ss.str()
|
---|
33 | #define BOOST_SPIRIT_OSSTREAM std::ostringstream
|
---|
34 | #endif
|
---|
35 |
|
---|
36 | namespace boost { namespace spirit {
|
---|
37 |
|
---|
38 | // xml formatting helper classes
|
---|
39 | namespace xml {
|
---|
40 |
|
---|
41 | inline void
|
---|
42 | encode (std::string &str, char s, char const *r, int len)
|
---|
43 | {
|
---|
44 | std::string::size_type pos = 0;
|
---|
45 | while ((pos = str.find_first_of (s, pos)) !=
|
---|
46 | std::string::size_type(std::string::npos))
|
---|
47 | {
|
---|
48 | str.replace (pos, 1, r);
|
---|
49 | pos += len;
|
---|
50 | }
|
---|
51 | }
|
---|
52 |
|
---|
53 | inline std::string
|
---|
54 | encode (std::string str)
|
---|
55 | {
|
---|
56 | encode(str, '&', "&", 3);
|
---|
57 | encode(str, '<', "<", 2);
|
---|
58 | encode(str, '>', ">", 2);
|
---|
59 | encode(str, '\r', "\\r", 1);
|
---|
60 | encode(str, '\n', "\\n", 1);
|
---|
61 | return str;
|
---|
62 | }
|
---|
63 |
|
---|
64 | inline std::string
|
---|
65 | encode (char const *text)
|
---|
66 | {
|
---|
67 | return encode (std::string(text));
|
---|
68 | }
|
---|
69 |
|
---|
70 | // format a xml attribute
|
---|
71 | struct attribute
|
---|
72 | {
|
---|
73 | attribute()
|
---|
74 | {
|
---|
75 | }
|
---|
76 |
|
---|
77 | attribute (char const *key_, char const *value_) :
|
---|
78 | key (key_), value(value_)
|
---|
79 | {
|
---|
80 | }
|
---|
81 |
|
---|
82 | bool has_value()
|
---|
83 | {
|
---|
84 | return value.size() > 0;
|
---|
85 | }
|
---|
86 |
|
---|
87 | std::string key;
|
---|
88 | std::string value;
|
---|
89 | };
|
---|
90 |
|
---|
91 | inline std::ostream&
|
---|
92 | operator<< (std::ostream &ostrm, attribute const &attr)
|
---|
93 | {
|
---|
94 | if (0 == attr.key.size())
|
---|
95 | return ostrm;
|
---|
96 | ostrm << " " << encode(attr.key) << "=\"" << encode(attr.value) << "\"";
|
---|
97 | return ostrm;
|
---|
98 | }
|
---|
99 |
|
---|
100 | // output a xml element (base class, not used directly)
|
---|
101 | class element
|
---|
102 | {
|
---|
103 | protected:
|
---|
104 | element(std::ostream &ostrm_, bool incr_indent_ = true) :
|
---|
105 | ostrm(ostrm_), incr_indent(incr_indent_)
|
---|
106 | {
|
---|
107 | if (incr_indent) ++get_indent();
|
---|
108 | }
|
---|
109 | ~element()
|
---|
110 | {
|
---|
111 | if (incr_indent) --get_indent();
|
---|
112 | }
|
---|
113 |
|
---|
114 | public:
|
---|
115 | void output_space ()
|
---|
116 | {
|
---|
117 | for (int i = 0; i < get_indent(); i++)
|
---|
118 | ostrm << " ";
|
---|
119 | }
|
---|
120 |
|
---|
121 | protected:
|
---|
122 | int &get_indent()
|
---|
123 | {
|
---|
124 | static int indent;
|
---|
125 |
|
---|
126 | return indent;
|
---|
127 | }
|
---|
128 |
|
---|
129 | std::ostream &ostrm;
|
---|
130 | bool incr_indent;
|
---|
131 | };
|
---|
132 |
|
---|
133 | // a xml node
|
---|
134 | class node : public element
|
---|
135 | {
|
---|
136 | public:
|
---|
137 | node (std::ostream &ostrm_, char const *tag_, attribute &attr) :
|
---|
138 | element(ostrm_), tag(tag_)
|
---|
139 | {
|
---|
140 | output_space();
|
---|
141 | ostrm << "<" << tag_ << attr << ">\n";
|
---|
142 | }
|
---|
143 | node (std::ostream &ostrm_, char const *tag_) :
|
---|
144 | element(ostrm_), tag(tag_)
|
---|
145 | {
|
---|
146 | output_space();
|
---|
147 | ostrm << "<" << tag_ << ">\n";
|
---|
148 | }
|
---|
149 | ~node()
|
---|
150 | {
|
---|
151 | output_space();
|
---|
152 | ostrm << "</" << tag << ">\n";
|
---|
153 | }
|
---|
154 |
|
---|
155 | private:
|
---|
156 | std::string tag;
|
---|
157 | };
|
---|
158 |
|
---|
159 | class text : public element
|
---|
160 | {
|
---|
161 | public:
|
---|
162 | text (std::ostream &ostrm, char const *tag, char const *text) :
|
---|
163 | element(ostrm)
|
---|
164 | {
|
---|
165 | output_space();
|
---|
166 | ostrm << "<" << tag << ">" << encode(text)
|
---|
167 | << "</" << tag << ">\n";
|
---|
168 | }
|
---|
169 |
|
---|
170 | text (std::ostream &ostrm, char const *tag, char const *text,
|
---|
171 | attribute &attr) :
|
---|
172 | element(ostrm)
|
---|
173 | {
|
---|
174 | output_space();
|
---|
175 | ostrm << "<" << tag << attr << ">" << encode(text)
|
---|
176 | << "</" << tag << ">\n";
|
---|
177 | }
|
---|
178 |
|
---|
179 | text (std::ostream &ostrm, char const *tag, char const *text,
|
---|
180 | attribute &attr1, attribute &attr2) :
|
---|
181 | element(ostrm)
|
---|
182 | {
|
---|
183 | output_space();
|
---|
184 | ostrm << "<" << tag << attr1 << attr2 << ">" << encode(text)
|
---|
185 | << "</" << tag << ">\n";
|
---|
186 | }
|
---|
187 | };
|
---|
188 |
|
---|
189 | // a xml comment
|
---|
190 | class comment : public element
|
---|
191 | {
|
---|
192 | public:
|
---|
193 | comment (std::ostream &ostrm, char const *comment) :
|
---|
194 | element(ostrm, false)
|
---|
195 | {
|
---|
196 | if ('\0' != comment[0])
|
---|
197 | {
|
---|
198 | output_space();
|
---|
199 | ostrm << "<!-- " << encode(comment) << " -->\n";
|
---|
200 | }
|
---|
201 | }
|
---|
202 | };
|
---|
203 |
|
---|
204 | // a xml document
|
---|
205 | class document : public element
|
---|
206 | {
|
---|
207 | public:
|
---|
208 | document (std::ostream &ostrm) : element(ostrm)
|
---|
209 | {
|
---|
210 | get_indent() = -1;
|
---|
211 | ostrm << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
|
---|
212 | }
|
---|
213 |
|
---|
214 | document (std::ostream &ostrm, char const *mainnode, char const *dtd) :
|
---|
215 | element(ostrm)
|
---|
216 | {
|
---|
217 | get_indent() = -1;
|
---|
218 | ostrm << "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n";
|
---|
219 |
|
---|
220 | output_space();
|
---|
221 | ostrm << "<!DOCTYPE " << mainnode << " SYSTEM \"" << dtd
|
---|
222 | << "\">\n";
|
---|
223 | }
|
---|
224 | ~document()
|
---|
225 | {
|
---|
226 | BOOST_SPIRIT_ASSERT(-1 == get_indent());
|
---|
227 | }
|
---|
228 | };
|
---|
229 |
|
---|
230 | } // end of namespace xml
|
---|
231 |
|
---|
232 | namespace impl {
|
---|
233 |
|
---|
234 | // look up the rule name from the given parser_id
|
---|
235 | template <typename AssocContainerT>
|
---|
236 | inline typename AssocContainerT::value_type::second_type
|
---|
237 | get_rulename (AssocContainerT const &id_to_name_map,
|
---|
238 | boost::spirit::parser_id const &id)
|
---|
239 | {
|
---|
240 | typename AssocContainerT::const_iterator it = id_to_name_map.find(id);
|
---|
241 | if (it != id_to_name_map.end())
|
---|
242 | return (*it).second;
|
---|
243 | typedef typename AssocContainerT::value_type::second_type second_t;
|
---|
244 | return second_t();
|
---|
245 | }
|
---|
246 |
|
---|
247 | // dump a parse tree as xml
|
---|
248 | template <typename IteratorT, typename GetIdT, typename GetValueT>
|
---|
249 | inline void
|
---|
250 | token_to_xml (std::ostream &ostrm, IteratorT const &it, bool is_root,
|
---|
251 | GetIdT const &get_token_id, GetValueT const &get_token_value)
|
---|
252 | {
|
---|
253 | BOOST_SPIRIT_OSSTREAM stream;
|
---|
254 |
|
---|
255 | stream << get_token_id(*it) << std::ends;
|
---|
256 | xml::attribute token_id ("id", BOOST_SPIRIT_GETSTRING(stream).c_str());
|
---|
257 | xml::attribute is_root_attr ("is_root", is_root ? "1" : "");
|
---|
258 | xml::attribute nil;
|
---|
259 | xml::text(ostrm, "token", get_token_value(*it).c_str(),
|
---|
260 | token_id, is_root_attr.has_value() ? is_root_attr : nil);
|
---|
261 | }
|
---|
262 |
|
---|
263 | template <
|
---|
264 | typename TreeNodeT, typename AssocContainerT,
|
---|
265 | typename GetIdT, typename GetValueT
|
---|
266 | >
|
---|
267 | inline void
|
---|
268 | tree_node_to_xml (std::ostream &ostrm, TreeNodeT const &node,
|
---|
269 | AssocContainerT const& id_to_name_map, GetIdT const &get_token_id,
|
---|
270 | GetValueT const &get_token_value)
|
---|
271 | {
|
---|
272 | typedef typename TreeNodeT::const_iterator node_iter_t;
|
---|
273 | typedef
|
---|
274 | typename TreeNodeT::value_type::parse_node_t::const_iterator_t
|
---|
275 | value_iter_t;
|
---|
276 |
|
---|
277 | xml::attribute nil;
|
---|
278 | node_iter_t end = node.end();
|
---|
279 | for (node_iter_t it = node.begin(); it != end; ++it)
|
---|
280 | {
|
---|
281 | // output a node
|
---|
282 | xml::attribute id ("rule",
|
---|
283 | get_rulename(id_to_name_map, (*it).value.id()).c_str());
|
---|
284 | xml::node currnode (ostrm, "parsenode",
|
---|
285 | (*it).value.id() != 0 && id.has_value() ? id : nil);
|
---|
286 |
|
---|
287 | // first dump the value
|
---|
288 | std::size_t cnt = std::distance((*it).value.begin(), (*it).value.end());
|
---|
289 |
|
---|
290 | if (1 == cnt)
|
---|
291 | {
|
---|
292 | token_to_xml (ostrm, (*it).value.begin(),
|
---|
293 | (*it).value.is_root(), get_token_id, get_token_value);
|
---|
294 | }
|
---|
295 | else if (cnt > 1)
|
---|
296 | {
|
---|
297 | xml::node value (ostrm, "value");
|
---|
298 | bool is_root = (*it).value.is_root();
|
---|
299 |
|
---|
300 | value_iter_t val_end = (*it).value.end();
|
---|
301 | for (value_iter_t val_it = (*it).value.begin();
|
---|
302 | val_it != val_end; ++val_it)
|
---|
303 | {
|
---|
304 | token_to_xml (ostrm, val_it, is_root, get_token_id,
|
---|
305 | get_token_value);
|
---|
306 | }
|
---|
307 | }
|
---|
308 | tree_node_to_xml(ostrm, (*it).children, id_to_name_map,
|
---|
309 | get_token_id, get_token_value); // dump all subnodes
|
---|
310 | }
|
---|
311 | }
|
---|
312 |
|
---|
313 | template <typename TreeNodeT, typename AssocContainerT>
|
---|
314 | inline void
|
---|
315 | tree_node_to_xml (std::ostream &ostrm, TreeNodeT const &node,
|
---|
316 | AssocContainerT const& id_to_name_map)
|
---|
317 | {
|
---|
318 | typedef typename TreeNodeT::const_iterator node_iter_t;
|
---|
319 |
|
---|
320 | xml::attribute nil;
|
---|
321 | node_iter_t end = node.end();
|
---|
322 | for (node_iter_t it = node.begin(); it != end; ++it)
|
---|
323 | {
|
---|
324 | // output a node
|
---|
325 | xml::attribute id ("rule",
|
---|
326 | get_rulename(id_to_name_map, (*it).value.id()).c_str());
|
---|
327 | xml::node currnode (ostrm, "parsenode",
|
---|
328 | (*it).value.id() != parser_id() && id.has_value() ? id : nil);
|
---|
329 |
|
---|
330 | // first dump the value
|
---|
331 | if ((*it).value.begin() != (*it).value.end())
|
---|
332 | {
|
---|
333 | std::string tokens ((*it).value.begin(), (*it).value.end());
|
---|
334 |
|
---|
335 | if (tokens.size() > 0)
|
---|
336 | {
|
---|
337 | // output all subtokens as one string (for better readability)
|
---|
338 | xml::attribute is_root ("is_root",
|
---|
339 | (*it).value.is_root() ? "1" : "");
|
---|
340 | xml::text(ostrm, "value", tokens.c_str(),
|
---|
341 | is_root.has_value() ? is_root : nil);
|
---|
342 | }
|
---|
343 |
|
---|
344 | }
|
---|
345 | // dump all subnodes
|
---|
346 | tree_node_to_xml(ostrm, (*it).children, id_to_name_map);
|
---|
347 | }
|
---|
348 | }
|
---|
349 |
|
---|
350 | } // namespace impl
|
---|
351 |
|
---|
352 | // dump a parse tree as a xml stream (generic variant)
|
---|
353 | template <
|
---|
354 | typename TreeNodeT, typename AssocContainerT,
|
---|
355 | typename GetIdT, typename GetValueT
|
---|
356 | >
|
---|
357 | inline void
|
---|
358 | tree_to_xml (std::ostream &ostrm, TreeNodeT const &tree,
|
---|
359 | std::string const &input_line, AssocContainerT const& id_to_name,
|
---|
360 | GetIdT const &get_token_id, GetValueT const &get_token_value)
|
---|
361 | {
|
---|
362 | // generate xml dump
|
---|
363 | xml::document doc (ostrm, "parsetree", "parsetree.dtd");
|
---|
364 | xml::comment input (ostrm, input_line.c_str());
|
---|
365 | xml::attribute ver ("version", "1.0");
|
---|
366 | xml::node mainnode (ostrm, "parsetree", ver);
|
---|
367 |
|
---|
368 | impl::tree_node_to_xml (ostrm, tree, id_to_name, get_token_id,
|
---|
369 | get_token_value);
|
---|
370 | }
|
---|
371 |
|
---|
372 | // dump a parse tree as a xml steam (for character based parsers)
|
---|
373 | template <typename TreeNodeT, typename AssocContainerT>
|
---|
374 | inline void
|
---|
375 | tree_to_xml (std::ostream &ostrm, TreeNodeT const &tree,
|
---|
376 | std::string const &input_line, AssocContainerT const& id_to_name)
|
---|
377 | {
|
---|
378 | // generate xml dump
|
---|
379 | xml::document doc (ostrm, "parsetree", "parsetree.dtd");
|
---|
380 | xml::comment input (ostrm, input_line.c_str());
|
---|
381 | xml::attribute ver ("version", "1.0");
|
---|
382 | xml::node mainnode (ostrm, "parsetree", ver);
|
---|
383 |
|
---|
384 | impl::tree_node_to_xml (ostrm, tree, id_to_name);
|
---|
385 | }
|
---|
386 |
|
---|
387 | template <typename TreeNodeT>
|
---|
388 | inline void
|
---|
389 | tree_to_xml (std::ostream &ostrm, TreeNodeT const &tree,
|
---|
390 | std::string const &input_line)
|
---|
391 | {
|
---|
392 | return tree_to_xml(ostrm, tree, input_line,
|
---|
393 | std::map<boost::spirit::parser_id, std::string>());
|
---|
394 | }
|
---|
395 |
|
---|
396 | }} // namespace boost::spirit
|
---|
397 |
|
---|
398 | #undef BOOST_SPIRIT_OSSTREAM
|
---|
399 | #undef BOOST_SPIRIT_GETSTRING
|
---|
400 |
|
---|
401 | #endif // !defined(PARSE_TREE_XML_HPP)
|
---|