Line data Source code
1 : /*************************************************************************
2 : *
3 : * Copyright (c) 2012 Kohei Yoshida
4 : *
5 : * Permission is hereby granted, free of charge, to any person
6 : * obtaining a copy of this software and associated documentation
7 : * files (the "Software"), to deal in the Software without
8 : * restriction, including without limitation the rights to use,
9 : * copy, modify, merge, publish, distribute, sublicense, and/or sell
10 : * copies of the Software, and to permit persons to whom the
11 : * Software is furnished to do so, subject to the following
12 : * conditions:
13 : *
14 : * The above copyright notice and this permission notice shall be
15 : * included in all copies or substantial portions of the Software.
16 : *
17 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 : * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 : * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 : * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 : * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 : * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 : * OTHER DEALINGS IN THE SOFTWARE.
25 : *
26 : ************************************************************************/
27 :
28 : #ifndef __ORCUS_SAX_NS_PARSER_HPP__
29 : #define __ORCUS_SAX_NS_PARSER_HPP__
30 :
31 : #include "sax_parser.hpp"
32 : #include "xml_namespace.hpp"
33 :
34 : #include <boost/unordered_set.hpp>
35 : #include <boost/ptr_container/ptr_vector.hpp>
36 :
37 : namespace orcus {
38 :
39 0 : struct sax_ns_parser_element
40 : {
41 : xmlns_id_t ns; // element namespace
42 : pstring ns_alias; // element namespace alias
43 : pstring name; // element name
44 : const char* begin_pos; // position of the opening brace '<'.
45 : const char* end_pos; // position of the char after the closing brace '>'.
46 : };
47 :
48 0 : struct sax_ns_parser_attribute
49 : {
50 : xmlns_id_t ns; // attribute namespace
51 : pstring ns_alias; // attribute namespace alias
52 : pstring name; // attribute name
53 : pstring value; // attribute value
54 : };
55 :
56 : namespace __sax {
57 :
58 : struct entity_name
59 : {
60 : pstring ns;
61 : pstring name;
62 :
63 0 : entity_name(const pstring& _ns, const pstring& _name) :
64 0 : ns(_ns), name(_name) {}
65 :
66 0 : bool operator== (const entity_name& other) const
67 : {
68 0 : return other.ns == ns && other.name == name;
69 : }
70 :
71 : struct hash
72 : {
73 0 : size_t operator() (const entity_name& v) const
74 : {
75 : static pstring::hash hasher;
76 0 : return hasher(v.ns) + hasher(v.name);
77 : }
78 : };
79 : };
80 :
81 : typedef boost::unordered_set<pstring, pstring::hash> ns_keys_type;
82 : typedef boost::unordered_set<entity_name, entity_name::hash> entity_names_type;
83 :
84 0 : struct elem_scope
85 : {
86 : xmlns_id_t ns;
87 : pstring name;
88 : ns_keys_type ns_keys;
89 : };
90 :
91 : typedef boost::ptr_vector<elem_scope> elem_scopes_type;
92 :
93 : class pop_ns_by_key : std::unary_function<pstring, void>
94 : {
95 : xmlns_context& m_cxt;
96 : public:
97 0 : pop_ns_by_key(xmlns_context& cxt) : m_cxt(cxt) {}
98 0 : void operator() (const pstring& key)
99 : {
100 0 : m_cxt.pop(key);
101 0 : }
102 : };
103 :
104 : }
105 :
106 : /**
107 : * SAX based XML parser with proper namespace handling.
108 : */
109 : template<typename _Handler>
110 : class sax_ns_parser
111 : {
112 : public:
113 : typedef _Handler handler_type;
114 :
115 : sax_ns_parser(const char* content, const size_t size, xmlns_context& ns_cxt, handler_type& handler);
116 : ~sax_ns_parser();
117 :
118 : void parse();
119 :
120 : private:
121 : /**
122 : * Re-route callbacks from the internal sax_parser into sax_ns_parser
123 : * callbacks.
124 : */
125 0 : class handler_wrapper
126 : {
127 : __sax::elem_scopes_type m_scopes;
128 : __sax::ns_keys_type m_ns_keys;
129 : __sax::entity_names_type m_attrs;
130 :
131 : sax_ns_parser_element m_elem;
132 : sax_ns_parser_attribute m_attr;
133 :
134 : xmlns_context& m_ns_cxt;
135 : handler_type& m_handler;
136 :
137 : bool m_declaration;
138 :
139 : public:
140 0 : handler_wrapper(xmlns_context& ns_cxt, handler_type& handler) : m_ns_cxt(ns_cxt), m_handler(handler), m_declaration(true) {}
141 :
142 0 : void declaration()
143 : {
144 0 : m_declaration = false;
145 0 : m_handler.declaration();
146 0 : }
147 :
148 0 : void start_element(const sax_parser_element& elem)
149 : {
150 0 : m_scopes.push_back(new __sax::elem_scope);
151 0 : __sax::elem_scope& scope = m_scopes.back();
152 0 : scope.ns = m_ns_cxt.get(elem.ns);
153 : scope.name = elem.name;
154 0 : scope.ns_keys.swap(m_ns_keys);
155 :
156 0 : m_elem.ns = scope.ns;
157 : m_elem.ns_alias = elem.ns;
158 : m_elem.name = scope.name;
159 0 : m_elem.begin_pos = elem.begin_pos;
160 0 : m_elem.end_pos = elem.end_pos;
161 0 : m_handler.start_element(m_elem);
162 :
163 0 : m_attrs.clear();
164 0 : }
165 :
166 0 : void end_element(const sax_parser_element& elem)
167 : {
168 0 : __sax::elem_scope& scope = m_scopes.back();
169 0 : if (scope.ns != m_ns_cxt.get(elem.ns) || scope.name != elem.name)
170 0 : throw malformed_xml_error("mis-matching closing element.");
171 :
172 0 : m_elem.ns = scope.ns;
173 : m_elem.ns_alias = elem.ns;
174 : m_elem.name = scope.name;
175 0 : m_elem.begin_pos = elem.begin_pos;
176 0 : m_elem.end_pos = elem.end_pos;
177 0 : m_handler.end_element(m_elem);
178 :
179 : // Pop all namespaces declared in this scope.
180 0 : std::for_each(scope.ns_keys.begin(), scope.ns_keys.end(), __sax::pop_ns_by_key(m_ns_cxt));
181 :
182 0 : m_scopes.pop_back();
183 0 : }
184 :
185 0 : void characters(const pstring& val)
186 : {
187 0 : m_handler.characters(val);
188 0 : }
189 :
190 0 : void attribute(const pstring& ns, const pstring& name, const pstring& val)
191 : {
192 0 : if (m_declaration)
193 : {
194 : // XML declaration attribute. Pass it through to the handler without namespace.
195 0 : m_handler.attribute(name, val);
196 0 : return;
197 : }
198 :
199 0 : if (m_attrs.count(__sax::entity_name(ns, name)) > 0)
200 0 : throw malformed_xml_error("You can't define two attributes of the same name in the same element.");
201 :
202 0 : m_attrs.insert(__sax::entity_name(ns, name));
203 :
204 0 : if (ns.empty() && name == "xmlns")
205 : {
206 : // Default namespace
207 0 : m_ns_cxt.push(pstring(), val);
208 0 : m_ns_keys.insert(pstring());
209 0 : return;
210 : }
211 :
212 0 : if (ns == "xmlns")
213 : {
214 : // Namespace alias
215 0 : if (!name.empty())
216 : {
217 0 : m_ns_cxt.push(name, val);
218 0 : m_ns_keys.insert(name);
219 : }
220 : return;
221 : }
222 :
223 0 : m_attr.ns = m_ns_cxt.get(ns);
224 : m_attr.ns_alias = ns;
225 : m_attr.name = name;
226 : m_attr.value = val;
227 0 : m_handler.attribute(m_attr);
228 : }
229 : };
230 :
231 : private:
232 : handler_wrapper m_wrapper;
233 : sax_parser<handler_wrapper> m_parser;
234 : };
235 :
236 : template<typename _Handler>
237 0 : sax_ns_parser<_Handler>::sax_ns_parser(
238 : const char* content, const size_t size, xmlns_context& ns_cxt, handler_type& handler) :
239 0 : m_wrapper(ns_cxt, handler), m_parser(content, size, m_wrapper)
240 : {
241 0 : }
242 :
243 : template<typename _Handler>
244 0 : sax_ns_parser<_Handler>::~sax_ns_parser()
245 : {
246 0 : }
247 :
248 : template<typename _Handler>
249 0 : void sax_ns_parser<_Handler>::parse()
250 : {
251 0 : m_parser.parse();
252 0 : }
253 :
254 : }
255 :
256 : #endif
|