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 : #include "xml_map_tree.hpp"
29 : #include "orcus/global.hpp"
30 :
31 : #define ORCUS_DEBUG_XML_MAP_TREE 0
32 :
33 : #if ORCUS_DEBUG_XML_MAP_TREE
34 : #include <iostream>
35 : #endif
36 :
37 : using namespace std;
38 :
39 : namespace orcus {
40 :
41 : namespace {
42 :
43 : class find_by_name : std::unary_function<xml_map_tree::linkable, bool>
44 : {
45 : xmlns_id_t m_ns;
46 : pstring m_name;
47 : public:
48 0 : find_by_name(xmlns_id_t ns, const pstring& name) : m_ns(ns), m_name(name) {}
49 0 : bool operator() (const xml_map_tree::linkable& e) const
50 : {
51 0 : return m_ns == e.ns && m_name == e.name;
52 : }
53 : };
54 :
55 : class xpath_parser
56 : {
57 : const xmlns_context& m_cxt;
58 : const char* mp_char;
59 : const char* mp_end;
60 :
61 : enum token_type { element, attribute };
62 : token_type m_next_token_type;
63 :
64 : public:
65 :
66 0 : struct token
67 : {
68 : xmlns_id_t ns;
69 : pstring name;
70 : bool attribute;
71 :
72 : token(xmlns_id_t _ns, const pstring& _name, bool _attribute) :
73 0 : ns(_ns), name(_name), attribute(_attribute)
74 : {
75 : #if ORCUS_DEBUG_XML_MAP_TREE
76 : cout << "xpath_parser::token: (ns='" << (ns ? ns : "none") << "', name='" << name << "', attribute=" << attribute << ")" << endl;
77 : #endif
78 : }
79 :
80 0 : token() : ns(XMLNS_UNKNOWN_ID), attribute(false) {}
81 : token(const token& r) : ns(r.ns), name(r.name), attribute(r.attribute) {}
82 : };
83 :
84 0 : xpath_parser(const xmlns_context& cxt, const char* p, size_t n) :
85 0 : m_cxt(cxt), mp_char(p), mp_end(p+n), m_next_token_type(element)
86 : {
87 0 : if (!n)
88 0 : throw xml_map_tree::xpath_error("empty path");
89 :
90 0 : if (*p != '/')
91 0 : throw xml_map_tree::xpath_error("first character must be '/'.");
92 :
93 0 : ++mp_char;
94 0 : }
95 :
96 0 : token next()
97 : {
98 0 : if (mp_char == mp_end)
99 : return token();
100 :
101 : const char* p0 = NULL;
102 : size_t len = 0;
103 : xmlns_id_t ns = XMLNS_UNKNOWN_ID;
104 :
105 0 : for (; mp_char != mp_end; ++mp_char, ++len)
106 : {
107 0 : if (!p0)
108 : {
109 : p0 = mp_char;
110 : len = 0;
111 : }
112 :
113 0 : switch (*mp_char)
114 : {
115 : case '/':
116 : {
117 : // '/' encountered. Next token is an element name.
118 0 : if (m_next_token_type == attribute)
119 0 : throw xml_map_tree::xpath_error("attribute name should not contain '/'.");
120 :
121 0 : m_next_token_type = element;
122 0 : ++mp_char; // skip the '/'.
123 : return token(ns, pstring(p0, len), false);
124 : }
125 : case '@':
126 : {
127 : // '@' encountered. Next token is an attribute name.
128 0 : m_next_token_type = attribute;
129 0 : ++mp_char; // skip the '@'.
130 : return token(ns, pstring(p0, len), false);
131 : }
132 : case ':':
133 : {
134 : // What comes ':' is a namespace. Reset the name and
135 : // convert the namespace to a proper ID.
136 : pstring ns_name(p0, len);
137 0 : ns = m_cxt.get(ns_name);
138 : p0 = NULL; // reset the name.
139 : }
140 0 : break;
141 : default:
142 : ;
143 : }
144 : }
145 :
146 : // '/' has never been encountered. It must be the last name in the path.
147 0 : return token(ns, pstring(p0, len), m_next_token_type == attribute);
148 : }
149 : };
150 :
151 : template<typename T>
152 : void print_element_stack(ostream& os, const T& elem_stack)
153 : {
154 : typename T::const_iterator it = elem_stack.begin(), it_end = elem_stack.end();
155 : for (; it != it_end; ++it)
156 : {
157 : const xml_map_tree::element& elem = **it;
158 : os << '/' << elem.name;
159 : }
160 : }
161 :
162 : }
163 :
164 0 : xml_map_tree::xpath_error::xpath_error(const string& msg) : general_error(msg) {}
165 :
166 0 : xml_map_tree::cell_position::cell_position() :
167 0 : row(-1), col(-1) {}
168 :
169 0 : xml_map_tree::cell_position::cell_position(const pstring& _sheet, spreadsheet::row_t _row, spreadsheet::col_t _col) :
170 0 : sheet(_sheet), row(_row), col(_col) {}
171 :
172 0 : xml_map_tree::cell_position::cell_position(const cell_position& r) :
173 0 : sheet(r.sheet), row(r.row), col(r.col) {}
174 :
175 0 : xml_map_tree::element_position::element_position() :
176 0 : open_begin(NULL), open_end(NULL), close_begin(NULL), close_end(NULL) {}
177 :
178 0 : xml_map_tree::cell_reference::cell_reference() {}
179 :
180 0 : xml_map_tree::range_reference::range_reference(const cell_position& _pos) :
181 0 : pos(_pos), row_size(0) {}
182 :
183 0 : xml_map_tree::linkable::linkable(xmlns_id_t _ns, const pstring& _name, linkable_node_type _node_type) :
184 0 : ns(_ns), name(_name), node_type(_node_type) {}
185 :
186 0 : xml_map_tree::attribute::attribute(xmlns_id_t _ns, const pstring& _name, reference_type _ref_type) :
187 0 : linkable(_ns, _name, node_attribute), ref_type(_ref_type)
188 : {
189 0 : switch (ref_type)
190 : {
191 : case reference_cell:
192 0 : cell_ref = new cell_reference;
193 0 : break;
194 : case reference_range_field:
195 0 : field_ref = new field_in_range;
196 0 : break;
197 : default:
198 0 : throw general_error("unexpected reference type in the constructor of attribute.");
199 : }
200 0 : }
201 :
202 0 : xml_map_tree::attribute::~attribute()
203 : {
204 0 : switch (ref_type)
205 : {
206 : case reference_cell:
207 0 : delete cell_ref;
208 : break;
209 : case reference_range_field:
210 0 : delete field_ref;
211 0 : break;
212 : default:
213 0 : throw general_error("unexpected reference type in the destructor of attribute.");
214 : }
215 0 : }
216 :
217 0 : xml_map_tree::element::element(
218 : xmlns_id_t _ns, const pstring& _name, element_type _elem_type, reference_type _ref_type) :
219 : linkable(_ns, _name, node_element),
220 : elem_type(_elem_type),
221 : ref_type(_ref_type),
222 0 : range_parent(NULL)
223 : {
224 0 : if (elem_type == element_unlinked)
225 : {
226 0 : child_elements = new element_store_type;
227 0 : return;
228 : }
229 :
230 0 : assert(elem_type == element_linked);
231 :
232 0 : switch (ref_type)
233 : {
234 : case reference_cell:
235 0 : cell_ref = new cell_reference;
236 0 : break;
237 : case reference_range_field:
238 0 : field_ref = new field_in_range;
239 0 : break;
240 : default:
241 0 : throw general_error("unexpected reference type in the constructor of element.");
242 : }
243 : }
244 :
245 0 : xml_map_tree::element::~element()
246 : {
247 0 : if (elem_type == element_unlinked)
248 : {
249 0 : delete child_elements;
250 : return;
251 : }
252 :
253 0 : assert(elem_type == element_linked);
254 :
255 0 : switch (ref_type)
256 : {
257 : case reference_cell:
258 0 : delete cell_ref;
259 : break;
260 : case reference_range_field:
261 0 : delete field_ref;
262 0 : break;
263 : default:
264 0 : throw general_error("unexpected reference type in the destructor of element.");
265 : }
266 0 : }
267 :
268 0 : const xml_map_tree::element* xml_map_tree::element::get_child(xmlns_id_t _ns, const pstring& _name) const
269 : {
270 0 : if (elem_type != element_unlinked)
271 : return NULL;
272 :
273 0 : assert(child_elements);
274 :
275 : element_store_type::const_iterator it =
276 0 : std::find_if(child_elements->begin(), child_elements->end(), find_by_name(_ns, _name));
277 :
278 0 : return it == child_elements->end() ? NULL : &(*it);
279 : }
280 :
281 0 : bool xml_map_tree::element::unlinked_attribute_anchor() const
282 : {
283 0 : return elem_type == element_unlinked && ref_type == reference_unknown && !attributes.empty();
284 : }
285 :
286 0 : xml_map_tree::walker::walker(const xml_map_tree& parent) :
287 0 : m_parent(parent) {}
288 0 : xml_map_tree::walker::walker(const xml_map_tree::walker& r) :
289 0 : m_parent(r.m_parent), m_stack(r.m_stack), m_unlinked_stack(r.m_unlinked_stack) {}
290 :
291 0 : void xml_map_tree::walker::reset()
292 : {
293 : m_stack.clear();
294 : m_unlinked_stack.clear();
295 0 : }
296 :
297 0 : const xml_map_tree::element* xml_map_tree::walker::push_element(xmlns_id_t ns, const pstring& name)
298 : {
299 0 : if (!m_unlinked_stack.empty())
300 : {
301 : // We're still in the unlinked region.
302 0 : m_unlinked_stack.push_back(xml_name_t(ns, name));
303 0 : return NULL;
304 : }
305 :
306 0 : if (m_stack.empty())
307 : {
308 0 : if (!m_parent.mp_root)
309 : {
310 : // Tree is empty.
311 0 : m_unlinked_stack.push_back(xml_name_t(ns, name));
312 : return NULL;
313 : }
314 :
315 0 : const element* p = m_parent.mp_root;
316 0 : if (p->ns != ns || p->name != name)
317 : {
318 : // Names differ.
319 0 : m_unlinked_stack.push_back(xml_name_t(ns, name));
320 : return NULL;
321 : }
322 :
323 0 : m_stack.push_back(p);
324 0 : return p;
325 : }
326 :
327 0 : if (m_stack.back()->elem_type == element_unlinked)
328 : {
329 : // Check if the current element has a child of the same name.
330 0 : const element* p = m_stack.back()->get_child(ns, name);
331 0 : if (p)
332 : {
333 0 : m_stack.push_back(p);
334 0 : return p;
335 : }
336 : }
337 :
338 0 : m_unlinked_stack.push_back(xml_name_t(ns, name));
339 0 : return NULL;
340 : }
341 :
342 0 : const xml_map_tree::element* xml_map_tree::walker::pop_element(xmlns_id_t ns, const pstring& name)
343 : {
344 0 : if (!m_unlinked_stack.empty())
345 : {
346 : // We're in the unlinked region. Pop element from the unlinked stack.
347 0 : if (m_unlinked_stack.back().ns != ns || m_unlinked_stack.back().name != name)
348 0 : throw general_error("Closing element has a different name than the opening element. (unlinked stack)");
349 :
350 : m_unlinked_stack.pop_back();
351 :
352 0 : if (!m_unlinked_stack.empty())
353 : // We are still in the unlinked region.
354 : return NULL;
355 :
356 0 : return m_stack.empty() ? NULL : m_stack.back();
357 : }
358 :
359 0 : if (m_stack.empty())
360 0 : throw general_error("Element was popped while the stack was empty.");
361 :
362 0 : if (m_stack.back()->ns != ns || m_stack.back()->name != name)
363 0 : throw general_error("Closing element has a different name than the opening element. (linked stack)");
364 :
365 : m_stack.pop_back();
366 0 : return m_stack.empty() ? NULL : m_stack.back();
367 : }
368 :
369 0 : xml_map_tree::xml_map_tree(xmlns_repository& xmlns_repo) :
370 0 : m_xmlns_cxt(xmlns_repo.create_context()), mp_cur_range_ref(NULL), mp_root(NULL) {}
371 :
372 0 : xml_map_tree::~xml_map_tree()
373 : {
374 0 : std::for_each(m_field_refs.begin(), m_field_refs.end(), map_object_deleter<range_ref_map_type>());
375 0 : delete mp_root;
376 0 : }
377 :
378 0 : void xml_map_tree::set_namespace_alias(const pstring& alias, const pstring& uri)
379 : {
380 : #if ORCUS_DEBUG_XML_MAP_TREE
381 : cout << "xml_map_tree::set_namespace_alias: alias='" << alias << "', uri='" << uri << "'" << endl;
382 : #endif
383 : // We need to turn the alias string persistent because the xmlns context
384 : // doesn't intern the alias strings.
385 0 : pstring alias_safe = m_names.intern(alias).first;
386 0 : m_xmlns_cxt.push(alias_safe, uri);
387 0 : }
388 :
389 0 : xmlns_id_t xml_map_tree::get_namespace(const pstring& alias) const
390 : {
391 0 : return m_xmlns_cxt.get(alias);
392 : }
393 :
394 0 : void xml_map_tree::set_cell_link(const pstring& xpath, const cell_position& ref)
395 : {
396 0 : if (xpath.empty())
397 0 : return;
398 :
399 : #if ORCUS_DEBUG_XML_MAP_TREE
400 : cout << "xml_map_tree::set_cell_link: xpath='" << xpath << "' (ref=" << ref << ")" << endl;
401 : #endif
402 :
403 : element_list_type elem_stack;
404 0 : linkable* node = get_element_stack(xpath, reference_cell, elem_stack);
405 0 : assert(node);
406 0 : assert(!elem_stack.empty());
407 : cell_reference* cell_ref = NULL;
408 0 : switch (node->node_type)
409 : {
410 : case node_element:
411 0 : assert(static_cast<element*>(node)->cell_ref);
412 : cell_ref = static_cast<element*>(node)->cell_ref;
413 : break;
414 : case node_attribute:
415 0 : assert(static_cast<attribute*>(node)->cell_ref);
416 : cell_ref = static_cast<attribute*>(node)->cell_ref;
417 : break;
418 : default:
419 0 : throw general_error("unknown node type returned from get_element_stack call in xml_map_tree::set_cell_link().");
420 : }
421 :
422 0 : cell_ref->pos = ref;
423 : }
424 :
425 0 : void xml_map_tree::start_range()
426 : {
427 : m_cur_range_parent.clear();
428 0 : mp_cur_range_ref = NULL;
429 0 : }
430 :
431 0 : void xml_map_tree::append_range_field_link(const pstring& xpath, const cell_position& pos)
432 : {
433 0 : if (xpath.empty())
434 0 : return;
435 :
436 : range_reference* range_ref = NULL;
437 0 : range_ref_map_type::iterator it = m_field_refs.lower_bound(pos);
438 0 : if (it == m_field_refs.end() || m_field_refs.key_comp()(pos, it->first))
439 : {
440 : // This reference does not exist yet. Insert a new one.
441 :
442 : // Make sure the sheet name string is persistent.
443 : cell_position pos_safe = pos;
444 0 : pos_safe.sheet = m_names.intern(pos.sheet.get(), pos.sheet.size()).first;
445 :
446 0 : it = m_field_refs.insert(it, range_ref_map_type::value_type(pos_safe, new range_reference(pos_safe)));
447 : }
448 :
449 0 : range_ref = it->second;
450 0 : assert(range_ref);
451 :
452 0 : if (!mp_cur_range_ref)
453 0 : mp_cur_range_ref = range_ref;
454 :
455 : #if ORCUS_DEBUG_XML_MAP_TREE
456 : cout << "xml_map_tree::append_range_field_link: " << xpath << " (ref=" << pos << ")" << endl;
457 : #endif
458 : element_list_type elem_stack;
459 0 : linkable* node = get_element_stack(xpath, reference_range_field, elem_stack);
460 0 : if (elem_stack.size() < 2)
461 0 : throw xpath_error("Path of a range field link must be at least 2 levels.");
462 :
463 0 : switch (node->node_type)
464 : {
465 : case node_element:
466 : {
467 : element* p = static_cast<element*>(node);
468 0 : assert(p && p->ref_type == reference_range_field && p->field_ref);
469 0 : p->field_ref->ref = range_ref;
470 0 : p->field_ref->column_pos = range_ref->field_nodes.size();
471 :
472 0 : range_ref->field_nodes.push_back(p);
473 : }
474 0 : break;
475 : case node_attribute:
476 : {
477 : attribute* p = static_cast<attribute*>(node);
478 0 : assert(p && p->ref_type == reference_range_field && p->field_ref);
479 0 : p->field_ref->ref = range_ref;
480 0 : p->field_ref->column_pos = range_ref->field_nodes.size();
481 :
482 0 : range_ref->field_nodes.push_back(p);
483 : }
484 0 : break;
485 : default:
486 : ;
487 : }
488 :
489 : // Determine the deepest common element for all field link elements in the
490 : // current range reference.
491 0 : if (m_cur_range_parent.empty())
492 : {
493 : // First field link in this range.
494 : element_list_type::iterator it_end = elem_stack.end();
495 0 : if (node->node_type == node_element)
496 : --it_end; // Skip the linked element, which is used as a field in a range.
497 :
498 : --it_end; // Skip the next-up element, which is used to group a single record entry.
499 0 : m_cur_range_parent.assign(elem_stack.begin(), it_end);
500 : #if ORCUS_DEBUG_XML_MAP_TREE
501 : print_element_stack(cout, m_cur_range_parent);
502 : cout << endl;
503 : #endif
504 : }
505 : else
506 : {
507 : // Determine the deepest common element between the two.
508 : element_list_type::iterator it = elem_stack.begin(), it_end = elem_stack.end();
509 : element_list_type::iterator it_cur = m_cur_range_parent.begin(), it_cur_end = m_cur_range_parent.end();
510 0 : if (*it != *it_cur)
511 0 : throw xpath_error("Two field links in the same range reference start with different root elements.");
512 :
513 : ++it;
514 : ++it_cur;
515 :
516 0 : for (; it != it_end && it_cur != it_cur_end; ++it, ++it_cur)
517 : {
518 0 : if (*it == *it_cur)
519 0 : continue;
520 :
521 : // The two elements differ. Take their parent element as the new common element.
522 0 : m_cur_range_parent.assign(elem_stack.begin(), it); // current elemnt excluded.
523 : break;
524 : }
525 :
526 0 : if (m_cur_range_parent.empty())
527 0 : throw xpath_error("Two field links in the same range reference must at least share the first level of their paths.");
528 0 : }
529 : }
530 :
531 0 : void xml_map_tree::commit_range()
532 : {
533 0 : if (!mp_cur_range_ref)
534 : // Nothing to commit.
535 0 : return;
536 :
537 : #if ORCUS_DEBUG_XML_MAP_TREE
538 : cout << "parent element path for this range: ";
539 : element_list_type::iterator it = m_cur_range_parent.begin(), it_end = m_cur_range_parent.end();
540 : for (; it != it_end; ++it)
541 : cout << "/" << (**it).name;
542 : cout << endl;
543 : #endif
544 :
545 0 : assert(!m_cur_range_parent.empty());
546 : // Mark the range parent element.
547 0 : m_cur_range_parent.back()->range_parent = mp_cur_range_ref;
548 : }
549 :
550 0 : const xml_map_tree::linkable* xml_map_tree::get_link(const pstring& xpath) const
551 : {
552 0 : if (!mp_root)
553 : return NULL;
554 :
555 0 : if (xpath.empty())
556 : return NULL;
557 :
558 : #if ORCUS_DEBUG_XML_MAP_TREE
559 : cout << "xml_map_tree::get_link: xpath = '" << xpath << "'" << endl;
560 : #endif
561 : const linkable* cur_node = mp_root;
562 :
563 0 : xpath_parser parser(m_xmlns_cxt, xpath.get(), xpath.size());
564 :
565 : // Check the root element first.
566 0 : xpath_parser::token token = parser.next();
567 0 : if (cur_node->ns != token.ns || cur_node->name != token.name)
568 : // Root element name doesn't match.
569 : return NULL;
570 :
571 : #if ORCUS_DEBUG_XML_MAP_TREE
572 : cout << "xml_map_tree::get_link: root = (ns=" << token.ns << ", name=" << token.name << ")" << endl;
573 : #endif
574 0 : for (token = parser.next(); !token.name.empty(); token = parser.next())
575 : {
576 0 : if (token.attribute)
577 : {
578 : // The current node should be an element and should have an attribute of the same name.
579 0 : if (cur_node->node_type != node_element)
580 : return NULL;
581 :
582 : const element* elem = static_cast<const element*>(cur_node);
583 : const attribute_store_type& attrs = elem->attributes;
584 : attribute_store_type::const_iterator it =
585 0 : std::find_if(attrs.begin(), attrs.end(), find_by_name(token.ns, token.name));
586 :
587 0 : if (it == attrs.end())
588 : // No such attribute exists.
589 : return NULL;
590 :
591 : return &(*it);
592 : }
593 :
594 : // See if an element of this name exists below the current element.
595 :
596 0 : if (cur_node->node_type != node_element)
597 : return NULL;
598 :
599 : const element* elem = static_cast<const element*>(cur_node);
600 0 : if (elem->elem_type != element_unlinked)
601 : return NULL;
602 :
603 0 : if (!elem->child_elements)
604 : return NULL;
605 :
606 : element_store_type::const_iterator it =
607 : std::find_if(
608 : elem->child_elements->begin(), elem->child_elements->end(),
609 0 : find_by_name(token.ns, token.name));
610 :
611 0 : if (it == elem->child_elements->end())
612 : // No such child element exists.
613 : return NULL;
614 :
615 : cur_node = &(*it);
616 : }
617 :
618 0 : if (cur_node->node_type != node_element || static_cast<const element*>(cur_node)->elem_type == element_unlinked)
619 : // Non-leaf elements are not links.
620 : return NULL;
621 :
622 : return cur_node;
623 : }
624 :
625 0 : xml_map_tree::walker xml_map_tree::get_tree_walker() const
626 : {
627 0 : return walker(*this);
628 : }
629 :
630 0 : xml_map_tree::range_ref_map_type& xml_map_tree::get_range_references()
631 : {
632 0 : return m_field_refs;
633 : }
634 :
635 0 : pstring xml_map_tree::intern_string(const pstring& str) const
636 : {
637 0 : return m_names.intern(str).first;
638 : }
639 :
640 0 : xml_map_tree::linkable* xml_map_tree::get_element_stack(
641 : const pstring& xpath, reference_type ref_type, element_list_type& elem_stack)
642 : {
643 0 : assert(!xpath.empty());
644 0 : xpath_parser parser(m_xmlns_cxt,xpath.get(), xpath.size());
645 :
646 : element_list_type elem_stack_new;
647 :
648 : // Get the root element first.
649 0 : xpath_parser::token token = parser.next();
650 0 : if (mp_root)
651 : {
652 : // Make sure the root element's names are the same.
653 0 : if (mp_root->ns != token.ns || mp_root->name != token.name)
654 0 : throw xpath_error("path begins with inconsistent root level name.");
655 : }
656 : else
657 : {
658 : // First time the root element is encountered.
659 0 : if (token.attribute)
660 0 : throw xpath_error("root element cannot be an attribute.");
661 :
662 : mp_root = new element(
663 0 : token.ns, m_names.intern(token.name.get(), token.name.size()).first,
664 0 : element_unlinked, reference_unknown);
665 : }
666 :
667 0 : elem_stack_new.push_back(mp_root);
668 0 : element* cur_element = elem_stack_new.back();
669 0 : assert(cur_element);
670 0 : assert(cur_element->child_elements);
671 :
672 0 : token = parser.next();
673 0 : for (xpath_parser::token token_next = parser.next(); !token_next.name.empty(); token_next = parser.next())
674 : {
675 : // Check if the current element contains a child element of the same name.
676 0 : if (token.attribute)
677 0 : throw xpath_error("attribute must always be at the end of the path.");
678 :
679 0 : element_store_type& children = *cur_element->child_elements;
680 0 : element_store_type::iterator it = std::find_if(children.begin(), children.end(), find_by_name(token.ns, token.name));
681 0 : if (it == children.end())
682 : {
683 : // Insert a new element of this name.
684 : children.push_back(
685 : new element(
686 0 : token.ns, m_names.intern(token.name.get(), token.name.size()).first,
687 0 : element_unlinked, reference_unknown));
688 0 : cur_element = &children.back();
689 : }
690 : else
691 0 : cur_element = &(*it);
692 :
693 0 : elem_stack_new.push_back(cur_element);
694 : token = token_next;
695 : }
696 :
697 0 : assert(cur_element);
698 :
699 : // Insert a leaf node.
700 :
701 : linkable* ret = NULL;
702 0 : if (token.attribute)
703 : {
704 : // This is an attribute. Insert it into the current element.
705 : attribute_store_type& attrs = cur_element->attributes;
706 :
707 : // Check if an attribute of the same name already exists.
708 0 : attribute_store_type::iterator it = std::find_if(attrs.begin(), attrs.end(), find_by_name(token.ns, token.name));
709 0 : if (it != attrs.end())
710 0 : throw xpath_error("This attribute is already linked. You can't link the same attribute twice.");
711 :
712 : attrs.push_back(
713 : new attribute(
714 0 : token.ns, m_names.intern(token.name.get(), token.name.size()).first, ref_type));
715 :
716 0 : ret = &attrs.back();
717 : }
718 : else
719 : {
720 : // Check if an element of the same name already exists.
721 0 : element_store_type& children = *cur_element->child_elements;
722 0 : element_store_type::iterator it = std::find_if(children.begin(), children.end(), find_by_name(token.ns, token.name));
723 0 : if (it == children.end())
724 : {
725 : // No element of that name exists.
726 : children.push_back(
727 : new element(
728 0 : token.ns, m_names.intern(token.name.get(), token.name.size()).first,
729 0 : element_linked, ref_type));
730 :
731 0 : elem_stack_new.push_back(&children.back());
732 0 : ret = &children.back();
733 : }
734 : else
735 : {
736 : // This element already exists. Check if this is already linked.
737 : element& elem = *it;
738 0 : if (elem.ref_type != reference_unknown || elem.elem_type != element_unlinked)
739 0 : throw xpath_error("This element is already linked. You can't link the same element twice.");
740 :
741 : // Turn this existing non-linked element into a linked one.
742 0 : delete elem.child_elements;
743 0 : elem.elem_type = element_linked;
744 0 : elem.ref_type = ref_type;
745 0 : switch (ref_type)
746 : {
747 : case reference_cell:
748 0 : elem.cell_ref = new cell_reference;
749 0 : break;
750 : case reference_range_field:
751 0 : elem.field_ref = new field_in_range;
752 0 : break;
753 : default:
754 0 : throw general_error("Unknown reference type in xml_map_tree::get_element_stack.");
755 : }
756 :
757 0 : elem_stack_new.push_back(&elem);
758 0 : ret = &elem;
759 : }
760 : }
761 :
762 : elem_stack.swap(elem_stack_new);
763 :
764 0 : return ret;
765 : }
766 :
767 0 : std::ostream& operator<< (std::ostream& os, const xml_map_tree::cell_position& ref)
768 : {
769 0 : os << "[sheet='" << ref.sheet << "' row=" << ref.row << " column=" << ref.col << "]";
770 0 : return os;
771 : }
772 :
773 0 : std::ostream& operator<< (std::ostream& os, const xml_map_tree::linkable& link)
774 : {
775 0 : if (!link.ns_alias.empty())
776 0 : os << link.ns_alias << ':';
777 0 : os << link.name;
778 0 : return os;
779 : }
780 :
781 0 : bool operator< (const xml_map_tree::cell_position& left, const xml_map_tree::cell_position& right)
782 : {
783 0 : if (left.sheet != right.sheet)
784 0 : return left.sheet < right.sheet;
785 :
786 0 : if (left.row != right.row)
787 0 : return left.row < right.row;
788 :
789 0 : return left.col < right.col;
790 : }
791 :
792 24 : }
793 :
|