1 /*=============================================================================
2 Copyright (c) 2017 Daniel James
4 Use, modification and distribution is subject to the Boost Software
5 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 http://www.boost.org/LICENSE_1_0.txt)
7 =============================================================================*/
9 #include "xml_parse.hpp"
10 #include "simple_parse.hpp"
20 void write_xml_tree_impl(
21 std::string
& out
, xml_element
* node
, unsigned int depth
);
23 void write_xml_tree(xml_element
* node
)
26 write_xml_tree_impl(result
, node
, 0);
27 quickbook::detail::out() << result
<< std::flush
;
30 void write_xml_tree_impl(
31 std::string
& out
, xml_element
* node
, unsigned int depth
)
37 for (unsigned i
= 0; i
< depth
; ++i
) {
40 switch (node
->type_
) {
41 case xml_element::element_node
:
45 case xml_element::element_text
:
48 case xml_element::element_html
:
52 out
+= "Unknown node type";
56 for (xml_element
* it
= node
->children(); it
; it
= it
->next()) {
57 write_xml_tree_impl(out
, it
, depth
+ 1);
66 string_iterator start
,
71 string_iterator start
,
73 void skip_question_mark_tag(
74 string_iterator
& it
, string_iterator start
, string_iterator end
);
75 void skip_exclamation_mark_tag(
76 string_iterator
& it
, string_iterator start
, string_iterator end
);
77 quickbook::string_view
read_tag_name(
78 string_iterator
& it
, string_iterator start
, string_iterator end
);
79 quickbook::string_view
read_attribute_value(
80 string_iterator
& it
, string_iterator start
, string_iterator end
);
81 quickbook::string_view
read_string(
82 string_iterator
& it
, string_iterator end
);
84 xml_tree
xml_parse(quickbook::string_view source
)
86 typedef string_iterator iterator
;
87 iterator it
= source
.begin(), end
= source
.end();
89 xml_tree_builder builder
;
93 read_to(it
, end
, '<');
95 builder
.add_element(xml_element::text_node(
96 quickbook::string_view(start
, it
- start
)));
104 throw xml_parse_error("Invalid tag", start
);
109 skip_question_mark_tag(it
, start
, end
);
112 skip_exclamation_mark_tag(it
, start
, end
);
115 read_close_tag(builder
, it
, start
, end
);
118 read_tag(builder
, it
, start
, end
);
123 return builder
.release();
127 xml_tree_builder
& builder
,
129 string_iterator start
,
132 assert(it
== start
+ 1 && it
!= end
);
133 quickbook::string_view name
= read_tag_name(it
, start
, end
);
134 xml_element
* node
= xml_element::node(name
);
135 builder
.add_element(node
);
139 read_some_of(it
, end
, " \t\n\r");
141 throw xml_parse_error("Invalid tag", start
);
145 builder
.start_children();
150 read_some_of(it
, end
, " \t\n\r");
151 if (it
== end
|| *it
!= '>') {
152 throw xml_parse_error("Invalid tag", start
);
157 quickbook::string_view attribute_name
=
158 read_tag_name(it
, start
, end
);
159 read_some_of(it
, end
, " \t\n\r");
161 throw xml_parse_error("Invalid tag", start
);
163 quickbook::string_view attribute_value
;
166 attribute_value
= read_attribute_value(it
, start
, end
);
170 quickbook::detail::decode_string(attribute_value
));
175 xml_tree_builder
& builder
,
177 string_iterator start
,
180 assert(it
== start
+ 1 && it
!= end
&& *it
== '/');
182 quickbook::string_view name
= read_tag_name(it
, start
, end
);
183 read_some_of(it
, end
, " \t\n\r");
184 if (it
== end
|| *it
!= '>') {
185 throw xml_parse_error("Invalid close tag", start
);
189 if (!builder
.parent() || builder
.parent()->name_
!= name
) {
190 throw xml_parse_error("Close tag doesn't match", start
);
193 builder
.end_children();
196 void skip_question_mark_tag(
197 string_iterator
& it
, string_iterator start
, string_iterator end
)
199 assert(it
== start
+ 1 && it
!= end
&& *it
== '?');
203 read_to_one_of(it
, end
, "\"'?<>");
205 throw xml_parse_error("Invalid tag", start
);
210 read_string(it
, end
);
213 if (read(it
, end
, "?>")) {
221 throw xml_parse_error("Invalid tag", start
);
226 void skip_exclamation_mark_tag(
227 string_iterator
& it
, string_iterator start
, string_iterator end
)
229 assert(it
== start
+ 1 && it
!= end
&& *it
== '!');
232 if (read(it
, end
, "--")) {
233 if (read_past(it
, end
, "-->")) {
237 throw xml_parse_error("Invalid comment", start
);
242 read_to_one_of(it
, end
, "\"'<>");
244 throw xml_parse_error("Invalid tag", start
);
249 read_string(it
, end
);
255 throw xml_parse_error("Invalid tag", start
);
260 quickbook::string_view
read_tag_name(
261 string_iterator
& it
, string_iterator start
, string_iterator end
)
263 read_some_of(it
, end
, " \t\n\r");
264 string_iterator name_start
= it
;
267 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:-");
268 if (name_start
== it
) {
269 throw xml_parse_error("Invalid tag", start
);
271 return quickbook::string_view(name_start
, it
- name_start
);
274 quickbook::string_view
read_attribute_value(
275 string_iterator
& it
, string_iterator start
, string_iterator end
)
277 read_some_of(it
, end
, " \t\n\r");
278 if (*it
== '"' || *it
== '\'') {
279 return read_string(it
, end
);
282 throw xml_parse_error("Invalid tag", start
);
286 quickbook::string_view
read_string(
287 string_iterator
& it
, string_iterator end
)
289 assert(it
!= end
&& (*it
== '"' || *it
== '\''));
291 string_iterator start
= it
;
292 char deliminator
= *it
;
294 read_to(it
, end
, deliminator
);
296 throw xml_parse_error("Invalid string", start
);
299 return quickbook::string_view(start
+ 1, it
- start
- 2);