NCBI C++ ToolKit
node.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /*
2  * Copyright (C) 2001-2003 Peter J Jones (pjones@pmade.org)
3  * 2009 Vaclav Slavik <vslavik@fastmail.fm>
4  * All Rights Reserved
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  * 3. Neither the name of the Author nor the names of its contributors
17  * may be used to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
24  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 /*
35  * $Id: node.cpp 101294 2023-11-28 14:10:36Z satskyse $
36  * NOTE: This file was modified from its original version 0.6.0
37  * to fit the NCBI C++ Toolkit build framework and
38  * API and functionality requirements.
39  * Most importantly, it adds support for XML namespaces (see "namespace.hpp").
40  */
41 
42 /** @file
43  * This file contains the implementation of the xml::node class.
44 **/
45 
46 // xmlwrapp includes
47 #include <misc/xmlwrapp/node.hpp>
52 #include "utility.hpp"
53 #include "ait_impl.hpp"
54 #include "node_manip.hpp"
55 #include "pimpl_base.hpp"
56 #include "node_iterator.hpp"
57 
58 // standard includes
59 #include <cstring>
60 #include <new>
61 #include <memory>
62 #include <string>
63 #include <vector>
64 #include <iostream>
65 #include <iterator>
66 #include <algorithm>
67 #include <stdexcept>
68 #include <functional>
69 
70 // libxml includes
71 #include <libxml/tree.h>
72 #include <libxml/parser.h>
73 #include <libxml/xpath.h>
74 #include <libxml/xpathInternals.h>
75 #include <libxml/xmlsave.h>
76 
77 // Workshop compiler define
78 #include <ncbiconf.h>
79 
80 using namespace xml;
81 using namespace xml::impl;
82 
83 
84 struct xml::impl::node_impl : public pimpl_base<xml::impl::node_impl> {
85 
86  node_impl (void) : xmlnode_(0), owner_(true), attrs_(0)
87  { }
88 
89  ~node_impl (void)
90  { release(); }
91 
92  void release (void) {
93  if (xmlnode_ && owner_) {
94  owner_ = false;
95  xmlFreeNode(xmlnode_);
96  }
97  }
98 
99  xmlNodePtr xmlnode_;
100  bool owner_;
103 };
104 
105 
107 {
108 
110 
111  bool operator() (xmlNodePtr lhs, xmlNodePtr rhs) {
112  xml::node l_node, r_node;
113  l_node.set_node_data(lhs);
114  r_node.set_node_data(rhs);
115 
116  return cb_(l_node, r_node);
117  }
118 
120 };
121 
122 
123 namespace {
124  // help turn a node into a document
125  class node2doc {
126  public:
127  node2doc (xmlNodePtr xmlnode) : xmlnode_(xmlnode), prev_(0), next_(0) {
128  xmldoc_ = xmlNewDoc(0);
129  if (!xmldoc_) throw std::bad_alloc();
130 
131  xmldoc_->children = xmlnode_;
132  xmldoc_->last = xmlnode_;
133 
134  std::swap(prev_, xmlnode_->prev);
135  std::swap(next_, xmlnode_->next);
136  }
137 
138  ~node2doc (void) {
139  xmldoc_->children = 0;
140  xmldoc_->last = 0;
141 
142  xmlFreeDoc(xmldoc_);
143 
144  std::swap(prev_, xmlnode_->prev);
145  std::swap(next_, xmlnode_->next);
146  }
147 
148  xmlDocPtr get_doc (void)
149  { return xmldoc_; }
150  private:
151  xmlDocPtr xmldoc_;
152  xmlNodePtr xmlnode_;
153  xmlNodePtr prev_;
154  xmlNodePtr next_;
155  };
156 
157  // sort compare function to sort based on attribute
158  struct compare_attr
159  {
160  compare_attr (const char *attr_name) : name_(attr_name) { }
161 
162  bool operator() (xmlNodePtr lhs, xmlNodePtr rhs) {
163  xmlAttrPtr attr_l, attr_r;
164  phantom_attr * dtd_l(0);
165  phantom_attr * dtd_r(0);
166 
167  attr_l = find_prop(lhs, name_, NULL);
168  if (attr_l == 0 &&
169  (dtd_l = find_default_prop(lhs, name_, NULL)) == 0)
170  return true;
171 
172  attr_r = find_prop(rhs, name_, NULL);
173  if (attr_r == 0 &&
174  (dtd_r = find_default_prop(rhs, name_, NULL)) == 0)
175  return false;
176 
177  xmlChar *value_l, *value_r;
178 
179  if (dtd_l) value_l = const_cast<xmlChar*>
180  (dtd_l->def_prop_->defaultValue);
181  else value_l = xmlNodeListGetString(lhs->doc, attr_l->children, 1);
182 
183  if (dtd_r) value_r = const_cast<xmlChar*>
184  (dtd_r->def_prop_->defaultValue);
185  else value_r = xmlNodeListGetString(rhs->doc, attr_r->children, 1);
186 
187  int rc = xmlStrcmp(value_l, value_r);
188 
189  if (!dtd_l) xmlFree(value_l);
190  if (!dtd_r) xmlFree(value_r);
191 
192  return rc < 0;
193  }
194 
195  const char *name_;
196  };
197 
198 
199  // add a node as a child
200  struct insert_node
201  {
202  insert_node (xmlNodePtr parent) : parent_(parent) { }
203  void operator() (xmlNodePtr child) { xmlAddChild(parent_, child); }
204 
205  xmlNodePtr parent_;
206  };
207 
208  // an element node finder
209  xmlNodePtr find_element(const char *name,
210  xmlNodePtr first, const ns *nspace) {
211  while (first != 0) {
212  if (first->type == XML_ELEMENT_NODE &&
213  xmlStrcmp(first->name,
214  reinterpret_cast<const xmlChar*>(name)) == 0) {
215  if (ns_util::node_ns_match(first, nspace))
216  return first;
217  }
218  first = first->next;
219  }
220 
221  return 0;
222  }
223 
224  #if 0
225  // Not used anymore
226  xmlNodePtr find_element(xmlNodePtr first) {
227  while (first != 0) {
228  if (first->type == XML_ELEMENT_NODE) return first;
229  first = first->next;
230  }
231 
232  return 0;
233  }
234  #endif
235 
236  // The function recursively fixes the switches the document pointer except
237  // of the highest level node
238  void set_new_doc(xmlNodePtr node, xmlDocPtr old_doc,
239  xmlDocPtr new_doc,
240  bool nested) {
241  if (node == NULL)
242  return;
243 
244  if (nested)
245  if (node->doc == old_doc)
246  node->doc = new_doc;
247 
248  xmlNsPtr def = node->nsDef;
249  while (def) {
250  if (def->context == old_doc)
251  def->context = new_doc;
252  def = def->next;
253  }
254 
255  xmlAttrPtr attr = node->properties;
256  while (attr) {
257  if (attr->doc == old_doc)
258  attr->doc = new_doc;
259  if (attr->children && attr->children->doc == old_doc)
260  attr->children->doc = new_doc;
261  attr = attr->next;
262  }
263 
264  node = node->children;
265  while (node) {
266  set_new_doc(node, old_doc, new_doc, true);
267  node = node->next;
268  }
269  }
270 
271  // Provides a distinctive list of namespaces which are recursively used
272  // in the node and defined outside of the node
273  void get_used_out_namespaces(xmlNodePtr node,
274  std::vector<xmlNsPtr> & definitions,
275  std::vector<xmlNsPtr> & namespaces) {
276  if (node == NULL)
277  return;
278 
279  xmlNsPtr def = node->nsDef;
280  while (def) {
281  definitions.push_back(def);
282  def = def->next;
283  }
284 
285  if (node->ns != NULL)
286  if (std::find(namespaces.begin(), namespaces.end(),
287  node->ns) == namespaces.end())
288  if (std::find(definitions.begin(), definitions.end(),
289  node->ns) == definitions.end())
290  namespaces.push_back(node->ns);
291 
292  xmlAttrPtr attr = node->properties;
293  while (attr) {
294  if (attr->ns != NULL)
295  if (std::find(namespaces.begin(), namespaces.end(),
296  attr->ns) == namespaces.end())
297  if (std::find(definitions.begin(), definitions.end(),
298  attr->ns) == definitions.end())
299  namespaces.push_back(attr->ns);
300  attr = attr->next;
301  }
302 
303  node = node->children;
304  while (node) {
305  get_used_out_namespaces(node, definitions, namespaces);
306  node = node->next;
307  }
308  }
309 
310  // Provides a list of namespace definitions defined above the given node
311  std::vector<xmlNsPtr> get_upper_namespaces(xmlNodePtr node) {
312  std::vector<xmlNsPtr> namespaces;
313  if (node == NULL)
314  return namespaces;
315 
316  node = node->parent;
317  while (node) {
318  xmlNsPtr def = node->nsDef;
319  while (def) {
320  namespaces.push_back(def);
321  def = def->next;
322  }
323  node = node->parent;
324  }
325  return namespaces;
326  }
327 
328  void update_ns_pointers(xmlNodePtr node,
329  xmlNsPtr old_ns, xmlNsPtr new_ns) {
330  if (node == NULL)
331  return;
332 
333  if (node->ns == old_ns)
334  node->ns = new_ns;
335 
336  xmlAttrPtr attr = node->properties;
337  while (attr) {
338  if (attr->ns == old_ns)
339  attr->ns = new_ns;
340  attr = attr->next;
341  }
342 
343  node = node->children;
344  while (node) {
345  update_ns_pointers(node, old_ns, new_ns);
346  node = node->next;
347  }
348  }
349 
350  bool in_doc_dict(xmlDocPtr doc, const xmlChar * s) {
351  if (doc == NULL)
352  return false;
353  if (doc->dict == NULL)
354  return false;
355  if (s == NULL)
356  return false;
357  return xmlDictOwns(doc->dict, s) == 1;
358  }
359 
360  void unlink_doc_dict(xmlDocPtr doc, xmlNodePtr node) {
361  if (doc == NULL)
362  return;
363  if (doc->dict == NULL)
364  return;
365  if (node == NULL)
366  return;
367 
368  if (in_doc_dict(doc, node->name))
369  node->name = xmlStrdup(node->name);
370  if (in_doc_dict(doc, node->content))
371  node->content = xmlStrdup(node->content);
372 
373  xmlAttrPtr attr = node->properties;
374  while (attr) {
375  if (in_doc_dict(doc, attr->name))
376  attr->name = xmlStrdup(attr->name);
377 
378  // Attribute value is stored in a child xmlNode which is always a
379  // single node and the field is 'content'
380  if (attr->children)
381  if (in_doc_dict(doc, attr->children->content))
382  attr->children->content = xmlStrdup(
383  attr->children->content);
384  attr = attr->next;
385  }
386 
387  node = node->children;
388  while (node) {
389  unlink_doc_dict(doc, node);
390  node = node->next;
391  }
392  }
393 }
394 
395 
397  pimpl_(new node_impl)
398 {}
399 
400 
402  pimpl_(new node_impl)
403 {
404  pimpl_->xmlnode_ = xmlNewNode(0,
405  reinterpret_cast<const xmlChar*>("blank"));
406  if (!pimpl_->xmlnode_) {
407  delete pimpl_;
408  throw std::bad_alloc();
409  }
410 }
411 
412 
413 xml::node::node (const char *name) :
414  pimpl_(new node_impl)
415 {
416  pimpl_->xmlnode_ = xmlNewNode(0, reinterpret_cast<const xmlChar*>(name));
417  if (!pimpl_->xmlnode_) {
418  delete pimpl_;
419  throw std::bad_alloc();
420  }
421 }
422 
423 
424 xml::node::node (const char *name, const char *content) :
425  pimpl_(new node_impl)
426 {
427  pimpl_->xmlnode_ = xmlNewNode(0, reinterpret_cast<const xmlChar*>(name));
428  if (!pimpl_->xmlnode_) {
429  delete pimpl_;
430  throw std::bad_alloc();
431  }
432 
433  xmlNodePtr content_node = xmlNewText(
434  reinterpret_cast<const xmlChar*>(content));
435  if (!content_node) {
436  delete pimpl_;
437  throw std::bad_alloc();
438  }
439 
440  if (!xmlAddChild(pimpl_->xmlnode_, content_node)) {
441  xmlFreeNode(content_node);
442  delete pimpl_;
443  throw std::bad_alloc();
444  }
445 }
446 
447 
448 xml::node::node (cdata cdata_info) :
449  pimpl_(new node_impl)
450 {
451  if ( (pimpl_->xmlnode_ =
452  xmlNewCDataBlock(0, reinterpret_cast<const xmlChar*>(cdata_info.t),
453  static_cast<int>(std::strlen(
454  cdata_info.t)))) == 0) {
455  delete pimpl_;
456  throw std::bad_alloc();
457  }
458 }
459 
460 
461 xml::node::node (comment comment_info) :
462  pimpl_(new node_impl)
463 {
464  if ( (pimpl_->xmlnode_ =
465  xmlNewComment(reinterpret_cast<const xmlChar*>(
466  comment_info.t))) == 0) {
467  delete pimpl_;
468  throw std::bad_alloc();
469  }
470 }
471 
472 
473 xml::node::node (pi pi_info) :
474  pimpl_(new node_impl)
475 {
476  if ( (pimpl_->xmlnode_ =
477  xmlNewPI(reinterpret_cast<const xmlChar*>(pi_info.n),
478  reinterpret_cast<const xmlChar*>(pi_info.c))) == 0) {
479  delete pimpl_;
480  throw std::bad_alloc();
481  }
482 }
483 
484 
485 xml::node::node (text text_info) :
486  pimpl_(new node_impl)
487 {
488  if ( (pimpl_->xmlnode_ =
489  xmlNewText(reinterpret_cast<const xmlChar*>(text_info.t))) == 0) {
490  delete pimpl_;
491  throw std::bad_alloc();
492  }
493 }
494 
495 
496 xml::node::node (const node &other) :
497  pimpl_(new node_impl)
498 {
499  pimpl_->xmlnode_ = xmlCopyNode(other.pimpl_->xmlnode_, 1);
500  if (!pimpl_->xmlnode_) {
501  delete pimpl_;
502  throw std::bad_alloc();
503  }
504 } /* NCBI_FAKE_WARNING */
505 
506 
508  node tmp_node(other); /* NCBI_FAKE_WARNING */
509  swap(tmp_node);
510  return *this;
511 }
512 
513 
515  node tmp_node(other); /* NCBI_FAKE_WARNING */
516  swap(tmp_node);
517  return *this;
518 }
519 
520 
522  try {
523  node* new_node = new node(*this); /* NCBI_FAKE_WARNING */
524  return new_node;
525  }
526  catch (std::exception & ex) {
527  throw xml::exception(ex.what());
528  }
529 }
530 
531 
533  pimpl_(other.pimpl_)
534 {
535  other.pimpl_ = NULL;
536 }
537 
538 
540 {
541  if (this != &other) {
542  if (pimpl_ != NULL)
543  delete pimpl_;
544  pimpl_ = other.pimpl_;
545  other.pimpl_ = NULL;
546  }
547  return *this;
548 }
549 
550 
551 void xml::node::swap (node &other) {
552 
553  if (pimpl_->xmlnode_ == other.pimpl_->xmlnode_)
554  return;
555 
556  // check if the nodes are nested into each other
557  if (pimpl_->xmlnode_->doc && other.pimpl_->xmlnode_->doc) {
558  if (pimpl_->xmlnode_->doc == other.pimpl_->xmlnode_->doc) {
559  xmlNodePtr parent = pimpl_->xmlnode_->parent;
560  while (parent) {
561  if (parent == other.pimpl_->xmlnode_)
562  throw xml::exception("a node cannot be swapped with "
563  "a node that it contains");
564  parent = parent->parent;
565  }
566  parent = other.pimpl_->xmlnode_->parent;
567  while (parent) {
568  if (parent == pimpl_->xmlnode_)
569  throw xml::exception("a node cannot be swapped with "
570  "a node that it contains");
571  parent = parent->parent;
572  }
573  }
574  }
575 
576  // deal with namespaces
577  // step 1: build a list of namespaces which are used from levels above
578  // the nodes to be swapped
579  std::vector<xmlNsPtr> self_ns_definitions;
580  std::vector<xmlNsPtr> other_ns_definitions;
581  std::vector<xmlNsPtr> self_used_out_namespaces;
582  std::vector<xmlNsPtr> other_used_out_namespaces;
583  get_used_out_namespaces(pimpl_->xmlnode_, self_ns_definitions,
584  self_used_out_namespaces);
585  get_used_out_namespaces(other.pimpl_->xmlnode_, other_ns_definitions,
586  other_used_out_namespaces);
587 
588  // step 2: compare the lists and leave only those namespaces which
589  // definitions differ
590  std::vector<xmlNsPtr>::iterator current = self_used_out_namespaces.begin();
591  std::vector<xmlNsPtr> other_definitions = get_upper_namespaces(
592  other.pimpl_->xmlnode_);
593  while (current != self_used_out_namespaces.end()) {
594  // try exact match - this might be the same document
595  std::vector<xmlNsPtr>::iterator found = std::find(
596  other_used_out_namespaces.begin(),
597  other_used_out_namespaces.end(),
598  *current);
599  if (found != other_used_out_namespaces.end()) {
600  current = self_used_out_namespaces.erase(current);
601  other_used_out_namespaces.erase(found);
602  continue;
603  }
604 
605  bool removed = false;
606  for (std::vector<xmlNsPtr>::const_iterator
607  k = other_definitions.begin();
608  k != other_definitions.end(); ++k) {
609  if ((*current)->href == (*k)->href &&
610  (*current)->prefix == (*k)->prefix) {
611  current = self_used_out_namespaces.erase(current);
612  removed = true;
613  break;
614  }
615  }
616 
617  if (!removed)
618  ++current;
619  }
620 
621  current = other_used_out_namespaces.begin();
622  std::vector<xmlNsPtr> self_definitions = get_upper_namespaces(
623  pimpl_->xmlnode_);
624  while (current != other_used_out_namespaces.end()) {
625  // No need to try the direct match, it was tested above
626  bool removed = false;
627  for (std::vector<xmlNsPtr>::const_iterator
628  k = self_definitions.begin();
629  k != self_definitions.end(); ++k) {
630  if ((*current)->href == (*k)->href &&
631  (*current)->prefix == (*k)->prefix) {
632  current = other_used_out_namespaces.erase(current);
633  removed = true;
634  break;
635  }
636  }
637 
638  if (!removed)
639  ++current;
640  }
641 
642  // step 3: introduce namespace definitions which are required for proper
643  // swapping and fix the namespace pointers
644  for (std::vector<xmlNsPtr>::const_iterator
645  k = self_used_out_namespaces.begin();
646  k != self_used_out_namespaces.end(); ++k) {
647  // Add namespace definition
648  xml::ns new_ns = add_namespace_def((const char *)((*k)->href),
649  (const char *)((*k)->prefix));
650  if ((*k)->prefix != NULL) {
651  // This is not a default namespace; if it was a default one then
652  // the pointers have been fixed in the add_namespace_def(...) call
653  // Otherwise the pointers need to be updated here.
654  update_ns_pointers(pimpl_->xmlnode_, *k,
655  xmlSearchNs(NULL, pimpl_->xmlnode_,
656  (*k)->prefix));
657  }
658  }
659 
660  for (std::vector<xmlNsPtr>::const_iterator
661  k = other_used_out_namespaces.begin();
662  k != other_used_out_namespaces.end(); ++k) {
663  // Add namespace definition
664  xml::ns new_ns = other.add_namespace_def((const char *)((*k)->href),
665  (const char *)((*k)->prefix));
666  if ((*k)->prefix != NULL) {
667  // This is not a default namespace; if it was a default one then
668  // the pointers have been fixed in the add_namespace_def(...) call
669  // Otherwise the pointers need to be updated here.
670  update_ns_pointers(other.pimpl_->xmlnode_, *k,
671  xmlSearchNs(NULL, other.pimpl_->xmlnode_,
672  (*k)->prefix));
673  }
674  }
675 
676  // Set the new document for the nested nodes recursively
677  xmlDocPtr self_doc = pimpl_->xmlnode_->doc;
678  xmlDocPtr other_doc = other.pimpl_->xmlnode_->doc;
679 
680  if (self_doc != other_doc) {
681  set_new_doc(pimpl_->xmlnode_, self_doc, other_doc, false);
682  set_new_doc(other.pimpl_->xmlnode_, other_doc, self_doc, false);
683  }
684 
685  if (self_doc != other_doc) {
686  // This is an inter-document swap.
687  // Let's invalidate default attribute iterators
688  if (self_doc)
689  invalidate_default_attr_iterators(pimpl_->xmlnode_);
690  if (other_doc)
692 
693  // Some node and attribute strings may come from a document dictionary
694  // so they need to be unlinked from the document
695  unlink_doc_dict(self_doc, pimpl_->xmlnode_);
696  unlink_doc_dict(other_doc, other.pimpl_->xmlnode_);
697  }
698 
699  // The name field was unlinked from the document above, if required
700  std::swap(pimpl_->xmlnode_->name, other.pimpl_->xmlnode_->name);
701 
702  if (pimpl_->xmlnode_->_private != nullptr
703  || other.pimpl_->xmlnode_->_private != nullptr) {
704  if (pimpl_->xmlnode_->_private == nullptr) {
705  impl::attach_node_private_data(pimpl_->xmlnode_);
706  }
707  if (other.pimpl_->xmlnode_->_private == nullptr) {
709  }
711  *priv = (node_private_data*)pimpl_->xmlnode_->_private,
712  *priv2 = (node_private_data*)other.pimpl_->xmlnode_->_private;
713  std::swap(priv->phantom_attrs_, priv2->phantom_attrs_);
714  std::swap(priv->attr_instances_, priv2->attr_instances_);
715  }
716  std::swap(pimpl_->xmlnode_->type, other.pimpl_->xmlnode_->type);
717  std::swap(pimpl_->xmlnode_->children, other.pimpl_->xmlnode_->children);
718  for (auto child = pimpl_->xmlnode_->children; child != nullptr;
719  child = child->next) {
720  child->parent = pimpl_->xmlnode_;
721  }
722  for (auto child = other.pimpl_->xmlnode_->children; child != nullptr;
723  child = child->next) {
724  child->parent = other.pimpl_->xmlnode_;
725  }
726  std::swap(pimpl_->xmlnode_->last, other.pimpl_->xmlnode_->last);
727  // parent, next, prev, doc are skipped because the top level xmlNode
728  // structure does not change its location
729  std::swap(pimpl_->xmlnode_->ns, other.pimpl_->xmlnode_->ns);
730  std::swap(pimpl_->xmlnode_->content, other.pimpl_->xmlnode_->content);
731  std::swap(pimpl_->xmlnode_->properties,
732  other.pimpl_->xmlnode_->properties);
733  std::swap(pimpl_->xmlnode_->nsDef, other.pimpl_->xmlnode_->nsDef);
734  std::swap(pimpl_->xmlnode_->psvi, other.pimpl_->xmlnode_->psvi);
735  std::swap(pimpl_->xmlnode_->line, other.pimpl_->xmlnode_->line);
736  std::swap(pimpl_->xmlnode_->extra, other.pimpl_->xmlnode_->extra);
737 }
738 
739 
741  if (pimpl_ != NULL)
742  delete pimpl_;
743 }
744 
745 
747  pimpl_->release();
748  pimpl_->xmlnode_ = static_cast<xmlNodePtr>(data);
749  pimpl_->owner_ = false;
750 }
751 
752 
753 void* xml::node::get_node_data (void) const {
754  return pimpl_->xmlnode_;
755 }
756 
757 
759  pimpl_->owner_ = false;
760  return pimpl_->xmlnode_;
761 }
762 
763 
764 void xml::node::set_name (const char *name) {
765  xmlNodeSetName(pimpl_->xmlnode_, reinterpret_cast<const xmlChar*>(name));
766 }
767 
768 
769 const char* xml::node::get_name (void) const {
770  return reinterpret_cast<const char*>(pimpl_->xmlnode_->name);
771 }
772 
773 
774 void xml::node::set_content (const char *content) {
775  if (pimpl_->xmlnode_->type == XML_ELEMENT_NODE && content != NULL) {
776  xmlChar * encoded_content =
777  xmlEncodeSpecialChars(
778  pimpl_->xmlnode_->doc,
779  reinterpret_cast<const xmlChar*>(content));
780  if (encoded_content == NULL)
781  throw std::bad_alloc();
782  xmlNodeSetContent(pimpl_->xmlnode_, encoded_content);
783  xmlFree(encoded_content);
784  return;
785  }
786  xmlNodeSetContent(pimpl_->xmlnode_,
787  reinterpret_cast<const xmlChar*>(content));
788 }
789 
790 
791 void xml::node::set_raw_content (const char *raw_content) {
792  xmlNodeSetContent(pimpl_->xmlnode_,
793  reinterpret_cast<const xmlChar*>(raw_content));
794 }
795 
796 
797 const char* xml::node::get_content (void) const {
798  xmlchar_helper content(xmlNodeGetContent(pimpl_->xmlnode_));
799  if (!content.get()) return 0;
800 
801  pimpl_->tmp_string = content.get();
802  return pimpl_->tmp_string.c_str();
803 }
804 
805 
807  switch (pimpl_->xmlnode_->type) {
808  case XML_ELEMENT_NODE: return type_element;
809  case XML_TEXT_NODE: return type_text;
810  case XML_CDATA_SECTION_NODE: return type_cdata;
811  case XML_ENTITY_REF_NODE: return type_entity_ref;
812  case XML_ENTITY_NODE: return type_entity;
813  case XML_PI_NODE: return type_pi;
814  case XML_COMMENT_NODE: return type_comment;
815  case XML_DOCUMENT_NODE: return type_document;
816  case XML_DOCUMENT_TYPE_NODE: return type_document_type;
817  case XML_DOCUMENT_FRAG_NODE: return type_document_frag;
818  case XML_NOTATION_NODE: return type_notation;
819  case XML_DTD_NODE: return type_dtd;
820  case XML_ELEMENT_DECL: return type_dtd_element;
821  case XML_ATTRIBUTE_DECL: return type_dtd_attribute;
822  case XML_ENTITY_DECL: return type_dtd_entity;
823  case XML_NAMESPACE_DECL: return type_dtd_namespace;
824  case XML_XINCLUDE_START: return type_xinclude;
825  case XML_XINCLUDE_END: return type_xinclude;
826  default: return type_element;
827  }
828 }
829 
830 
832  if (pimpl_->xmlnode_->type != XML_ELEMENT_NODE) {
833  throw xml::exception("get_attributes called on non-element node");
834  }
835 
836  pimpl_->attrs_.set_data(pimpl_->xmlnode_);
837  return pimpl_->attrs_;
838 }
839 
840 
842  if (pimpl_->xmlnode_->type != XML_ELEMENT_NODE) {
843  throw xml::exception("get_attributes called on non-element node");
844  }
845 
846  pimpl_->attrs_.set_data(pimpl_->xmlnode_);
847  return pimpl_->attrs_;
848 }
849 
850 
852  const ns* nspace) {
853  return get_attributes().find(name, nspace);
854 }
855 
856 
858 xml::node::find_attribute (const char* name, const ns* nspace) const {
859  return get_attributes().find(name, nspace);
860 }
861 
862 
864  if (type == xml::ns::type_safe_ns) {
865  return pimpl_->xmlnode_->ns
866  ? xml::ns(reinterpret_cast<const char*>(pimpl_->xmlnode_->ns->prefix),
867  reinterpret_cast<const char*>(pimpl_->xmlnode_->ns->href))
869  }
870  // unsafe namespace
871  return xml::ns(pimpl_->xmlnode_->ns);
872 }
873 
874 
877  return get_namespace_definitions(pimpl_->xmlnode_, type);
878 }
879 
880 
884  xml::ns_list_type namespace_definitions;
885  if (!reinterpret_cast<xmlNodePtr>(nd)->nsDef) {
886  return namespace_definitions;
887  }
888  for (xmlNs * ns(reinterpret_cast<xmlNodePtr>(nd)->nsDef);
889  ns; ns = ns->next) {
890  if (type == xml::ns::type_safe_ns) {
891  namespace_definitions.push_back(
892  xml::ns(reinterpret_cast<const char*>(ns->prefix),
893  reinterpret_cast<const char*>(ns->href)));
894  }
895  else {
896  namespace_definitions.push_back(xml::ns(ns));
897  }
898  }
899  return namespace_definitions;
900 }
901 
902 
903 xml::ns xml::node::set_namespace (const char *prefix) {
904  if (prefix && prefix[0] == '\0') prefix = NULL;
905  xmlNs * definition(xmlSearchNs(NULL,
906  pimpl_->xmlnode_,
907  reinterpret_cast<const xmlChar*>(prefix)));
908  if (!definition)
909  throw xml::exception("Namespace definition is not found");
910  pimpl_->xmlnode_->ns = definition;
911  return xml::ns(definition);
912 }
913 
914 
916  if (name_space.is_void()) {
917  erase_namespace();
918  // The erase_namespace updates the node->ns pointer approprietly
919  return xml::ns(pimpl_->xmlnode_->ns);
920  }
921  if (!name_space.is_safe()) {
922  pimpl_->xmlnode_->ns = reinterpret_cast<xmlNs*>(name_space.unsafe_ns_);
923  }
924  else {
925  const char * prefix(name_space.get_prefix());
926  if (prefix[0] == '\0') prefix = NULL;
927 
928  xmlNs * definition(xmlSearchNs(
929  NULL, pimpl_->xmlnode_,
930  reinterpret_cast<const xmlChar*>(prefix)));
931  if (!definition)
932  throw xml::exception("Namespace definition is not found");
933  if (!xmlStrEqual(
934  definition->href,
935  reinterpret_cast<const xmlChar*>(name_space.get_uri())))
936  throw xml::exception("Namespace definition URI "
937  "differs to the given");
938  pimpl_->xmlnode_->ns = definition;
939  }
940  return xml::ns(pimpl_->xmlnode_->ns);
941 }
942 
943 
944 xml::ns
947  if (name_space.is_void())
948  throw xml::exception("void namespace cannot be added "
949  "to namespace definitions");
950  if (!pimpl_->xmlnode_->nsDef)
951  return add_namespace_def(name_space.get_uri(),
952  name_space.get_prefix());
953 
954  // Search in the list of existed
955  const char * patternPrefix(name_space.get_prefix());
956  if (patternPrefix[0] == '\0') patternPrefix = NULL;
957 
958  xmlNs * current(pimpl_->xmlnode_->nsDef);
959  while (current) {
960  if (current->prefix == NULL) {
961  // Check if the default namespace matched
962  if (patternPrefix == NULL)
963  return add_matched_namespace_def(current, name_space.get_uri(),
964  type);
965  }
966  else {
967  // Check if a non default namespace matched
968  if (xmlStrEqual(reinterpret_cast<const xmlChar*>(patternPrefix),
969  current->prefix))
970  return add_matched_namespace_def(current, name_space.get_uri(),
971  type);
972  }
973  current = current->next;
974  }
975 
976  // Not found in the existed, so simply add the namespace
977  return add_namespace_def(name_space.get_uri(), name_space.get_prefix());
978 }
979 
980 
981 void
984  xml::ns_list_type::const_iterator first(name_spaces.begin()),
985  last(name_spaces.end());
986  for (; first != last; ++first) { add_namespace_definition(*first, type); }
987 }
988 
989 
990 xml::ns xml::node::add_namespace_def (const char *uri, const char *prefix) {
991  if (prefix && prefix[0] == '\0') prefix = NULL;
992  if (uri && uri[0] == '\0') uri = NULL;
993  xmlNs * newNs(xmlNewNs(pimpl_->xmlnode_,
994  reinterpret_cast<const xmlChar*>(uri),
995  reinterpret_cast<const xmlChar*>(prefix)));
996  if (!newNs)
997  throw std::bad_alloc();
998 
999  if (!prefix) {
1000  // The added namespace is the default. Set the default namespace to all
1001  // the nested nodes until another default namespace is not defined and
1002  // the nodes used the old default namespace
1003  if (!pimpl_->xmlnode_->ns || !pimpl_->xmlnode_->ns->prefix)
1004  pimpl_->xmlnode_->ns = newNs;
1005  update_children_default_ns(pimpl_->xmlnode_, newNs);
1006  }
1007  return xml::ns(newNs);
1008 }
1009 
1010 
1011 xml::ns
1012 xml::node::add_matched_namespace_def (void *libxml2RawNamespace,
1013  const char *uri,
1015  if (type == type_throw_if_exists)
1016  throw xml::exception("namespace is already defined");
1017  if (reinterpret_cast<xmlNs*>(libxml2RawNamespace)->href != NULL )
1018  xmlFree((char*)(reinterpret_cast<xmlNs*>(libxml2RawNamespace)->href));
1019  reinterpret_cast<xmlNs*>(libxml2RawNamespace)->href =
1020  xmlStrdup(reinterpret_cast<const xmlChar*>(uri));
1021  return xml::ns(libxml2RawNamespace);
1022 }
1023 
1024 
1026  xml::ns::ns_safety_type type) const {
1027  if (prefix && prefix[0] == '\0') prefix = NULL;
1028  xmlNs * found(xmlSearchNs(NULL, pimpl_->xmlnode_,
1029  reinterpret_cast<const xmlChar*>(prefix)));
1030 
1031  if (type == xml::ns::type_safe_ns) {
1032  if (found) return xml::ns(reinterpret_cast<const char*>(found->prefix),
1033  reinterpret_cast<const char*>(found->href));
1034  return xml::ns(xml::ns::type_void);
1035  }
1036  // Unsafe namespace requested
1037  return xml::ns(found);
1038 }
1039 
1040 
1041 void xml::node::erase_namespace_definition (const char *prefix,
1043  if (prefix && prefix[0] == '\0')
1044  prefix = NULL;
1045 
1046  // Search for the ns definition
1047  xmlNs *definition(lookup_ns_definition(pimpl_->xmlnode_, prefix));
1048  if (!definition)
1049  return; // Not found
1050 
1051  if (how == type_ns_def_erase_if_not_used) {
1052  // Here: remove if not in use
1053  if (is_ns_used(pimpl_->xmlnode_, definition))
1054  throw xml::exception( "Namespace is in use" );
1055 
1056  // Update the linked list pointers and free the namespace
1057  erase_ns_definition(pimpl_->xmlnode_, definition);
1058  return;
1059  }
1060 
1061  // Here: remove namespace even if in use
1062 
1063  // It is safe to remove the namespace definition because the places where
1064  // it is used are adjusted below anyway
1065  erase_ns_definition(pimpl_->xmlnode_, definition);
1066 
1067  // find a default namespace above. Could be null if no definition above
1068  // is found.
1069  xmlNs *default_namespace(lookup_default_ns_above(pimpl_->xmlnode_));
1070 
1071  // Replace the old ns with a new one recursively
1072  replace_ns(pimpl_->xmlnode_, definition, default_namespace);
1073  return;
1074 }
1075 
1076 
1078  if (!pimpl_->xmlnode_->ns) return;
1079  if (!pimpl_->xmlnode_->ns->prefix) return;
1080  pimpl_->xmlnode_->ns = xmlSearchNs(NULL, pimpl_->xmlnode_, NULL);
1081 }
1082 
1083 
1085  std::deque<xml::ns_list_type> definitions_stack;
1086  definitions_stack.push_front(
1087  get_namespace_definitions(xml::ns::type_unsafe_ns));
1088  return erase_duplicate_ns_defs(pimpl_->xmlnode_, definitions_stack);
1089 }
1090 
1091 
1093  std::deque<ns_list_type>& defs) {
1094  xmlNodePtr current = reinterpret_cast<xmlNodePtr>(nd)->children;
1095  while (current) {
1096  erase_duplicate_ns_defs_single_node(current, defs);
1097  defs.push_front(get_namespace_definitions(current,
1099  erase_duplicate_ns_defs(current, defs);
1100  defs.pop_front();
1101  current = current->next;
1102  }
1103 }
1104 
1105 
1106 void
1108  void* nd,
1109  std::deque<ns_list_type>& defs) {
1110  xmlNsPtr ns(reinterpret_cast<xmlNodePtr>(nd)->nsDef);
1111  while (ns) {
1112  xmlNsPtr replacement(
1113  reinterpret_cast<xmlNsPtr>(
1114  find_replacement_ns_def(defs, ns)));
1115  if (replacement) {
1116  replace_ns(reinterpret_cast<xmlNodePtr>(nd), ns, replacement);
1117  xmlNsPtr next(ns->next);
1118  erase_ns_definition(reinterpret_cast<xmlNodePtr>(nd), ns);
1119  ns = next;
1120  }
1121  else {
1122  ns = ns->next;
1123  }
1124  }
1125 }
1126 
1127 
1128 void* xml::node::find_replacement_ns_def (std::deque<ns_list_type>& defs,
1129  void* ns) {
1130  xmlNsPtr nspace(reinterpret_cast<xmlNsPtr>(ns));
1131  for (std::deque<ns_list_type>::const_iterator k(defs.begin());
1132  k != defs.end(); ++k) {
1133  for (ns_list_type::const_iterator j(k->begin()); j != k->end(); ++j) {
1134  if (xmlStrcmp(
1135  nspace->prefix,
1136  reinterpret_cast<xmlNsPtr>(j->unsafe_ns_)->prefix) == 0) {
1137  if (xmlStrcmp(
1138  nspace->href,
1139  reinterpret_cast<xmlNsPtr>
1140  (j->unsafe_ns_)->href) == 0) {
1141  return j->unsafe_ns_;
1142  }
1143  return NULL;
1144  }
1145  }
1146  }
1147  return NULL;
1148 }
1149 
1150 
1152  return erase_unused_ns_defs(pimpl_->xmlnode_);
1153 }
1154 
1155 
1157  // Node itsef
1158  xmlNsPtr ns(reinterpret_cast<xmlNodePtr>(nd)->nsDef);
1159  while (ns) {
1160  if (!is_ns_used(reinterpret_cast<xmlNodePtr>(nd), ns)) {
1161  xmlNsPtr next(ns->next);
1162  erase_ns_definition(reinterpret_cast<xmlNodePtr>(nd), ns);
1163  ns = next;
1164  }
1165  else {
1166  ns = ns->next;
1167  }
1168  }
1169  // Children
1170  xmlNodePtr current = reinterpret_cast<xmlNodePtr>(nd)->children;
1171  while (current) {
1172  erase_unused_ns_defs(current);
1173  current = current->next;
1174  }
1175 }
1176 
1177 
1179  xmlChar* path(xmlGetNodePath(pimpl_->xmlnode_));
1180  if (path) {
1181  std::string node_path(reinterpret_cast<const char*>(path));
1182  xmlFree(path);
1183  return node_path;
1184  }
1185  throw xml::exception("Cannot get node path");
1186 }
1187 
1188 
1189 bool xml::node::is_text (void) const {
1190  return xmlNodeIsText(pimpl_->xmlnode_) != 0;
1191 }
1192 
1193 
1194 void xml::node::push_back (const node &child) {
1195  xml::impl::node_insert(pimpl_->xmlnode_, 0, child.pimpl_->xmlnode_);
1196 }
1197 
1198 
1200  #ifdef NCBI_COMPILER_WORKSHOP
1201  xml::node::size_type dist(0);
1202  xml::node::const_iterator first(begin()), last(end());
1203  for (; first != last; ++first) { ++dist; }
1204  return dist;
1205  #else
1206  return static_cast<xml::node::size_type>(std::distance(begin(),
1207  end()));
1208  #endif
1209 }
1210 
1211 
1212 bool xml::node::empty (void) const {
1213  return pimpl_->xmlnode_->children == 0;
1214 }
1215 
1216 
1218  return iterator(pimpl_->xmlnode_->children);
1219 }
1220 
1221 
1223  return const_iterator(pimpl_->xmlnode_->children);
1224 }
1225 
1226 
1228  return iterator(pimpl_->xmlnode_);
1229 }
1230 
1231 
1233  return const_iterator(pimpl_->xmlnode_);
1234 }
1235 
1236 
1237 bool xml::node::is_root (void) const {
1238  if (pimpl_->xmlnode_->parent == NULL)
1239  return true;
1240  return pimpl_->xmlnode_->parent->type == XML_DOCUMENT_NODE;
1241 }
1242 
1243 
1245  if (is_root())
1246  iterator();
1247  return iterator(pimpl_->xmlnode_->parent);
1248 }
1249 
1250 
1252  if (is_root())
1253  const_iterator();
1254  return const_iterator(pimpl_->xmlnode_->parent);
1255 }
1256 
1257 
1259  const ns *nspace) {
1260  xmlNodePtr found = find_element(name, pimpl_->xmlnode_->children, nspace);
1261  if (found) return iterator(found);
1262  return end();
1263 }
1264 
1265 
1267  const ns *nspace) const {
1268  xmlNodePtr found = find_element(name, pimpl_->xmlnode_->children, nspace);
1269  if (found) return const_iterator(found);
1270  return end();
1271 }
1272 
1273 
1275  const iterator& start,
1276  const ns *nspace) {
1277  xmlNodePtr n = static_cast<xmlNodePtr>(start.get_raw_node());
1278  if ( (n = find_element(name, n, nspace))) return iterator(n);
1279  return end();
1280 }
1281 
1282 
1284  const const_iterator& start,
1285  const ns *nspace) const {
1286  xmlNodePtr n = static_cast<xmlNodePtr>(start.get_raw_node());
1287  if ( (n = find_element(name, n, nspace))) return const_iterator(n);
1288  return end();
1289 }
1290 
1291 
1293  xmlXPathContextPtr xpath_context(
1294  reinterpret_cast<xmlXPathContextPtr>(
1295  create_xpath_context(expr)));
1296  xmlXPathObjectPtr object(
1297  reinterpret_cast<xmlXPathObjectPtr>(
1299  xpath_context)));
1300  xmlXPathFreeContext(xpath_context);
1301 
1302  switch (object->type) {
1303  case XPATH_NODESET:
1304  return node_set(object);
1305  case XPATH_BOOLEAN: /* These three cases are the same */
1306  case XPATH_NUMBER:
1307  case XPATH_STRING:
1308  return convert_to_nset(object);
1309  default: ;
1310  }
1311  throw xml::exception("Unsupported xpath run result type");
1312 }
1313 
1314 
1315 const xml::node_set
1317  // Create a context
1318  xmlXPathContextPtr xpath_context(
1319  reinterpret_cast<xmlXPathContextPtr>(
1320  create_xpath_context(expr)));
1321  xmlXPathObjectPtr object(
1322  reinterpret_cast<xmlXPathObjectPtr>(
1324  xpath_context)));
1325  xmlXPathFreeContext(xpath_context);
1326 
1327  switch (object->type) {
1328  case XPATH_NODESET: /* These two cases are the same */
1329  case XPATH_XSLT_TREE:
1330  return node_set(object);
1331  case XPATH_BOOLEAN: /* These three cases are the same */
1332  case XPATH_NUMBER:
1333  case XPATH_STRING:
1334  return convert_to_nset(object);
1335  default: ;
1336  }
1337  throw xml::exception("Unsupported xpath run result type");
1338 }
1339 
1340 
1342  return run_xpath_query(xpath_expression(expr,
1343  get_effective_namespaces(type_ns_only_non_default)));
1344 }
1345 
1346 
1347 const xml::node_set xml::node::run_xpath_query (const char * expr) const {
1348  return run_xpath_query(xpath_expression(expr,
1349  get_effective_namespaces(type_ns_only_non_default)));
1350 }
1351 
1352 
1355  if (!pimpl_->xmlnode_)
1356  throw xml::exception("invalid node to get effective namespaces");
1357 
1358  ns_list_type nspaces;
1359  xmlNsPtr * nsList = xmlGetNsList(pimpl_->xmlnode_->doc,
1360  pimpl_->xmlnode_);
1361  xmlNsPtr * current = nsList;
1362 
1363  if (!nsList)
1364  return nspaces;
1365 
1366  while (*current != NULL) {
1367  switch (which) {
1368  case type_ns_only_default:
1369  if ((*current)->prefix == NULL)
1370  nspaces.push_back(ns(*current));
1371  break;
1372  case type_ns_only_non_default:
1373  if ((*current)->prefix != NULL)
1374  nspaces.push_back(ns(*current));
1375  break;
1376  case type_ns_all:
1377  nspaces.push_back(ns(*current));
1378  break;
1379  }
1380  ++current;
1381  }
1382 
1383  if (nsList)
1384  xmlFree(nsList);
1385  return nspaces;
1386 }
1387 
1388 
1389 void *
1391  if (!pimpl_->xmlnode_ || !pimpl_->xmlnode_->doc)
1392  throw xml::exception("cannot create xpath context "
1393  "(reference to document is not set)");
1394 
1395  xmlXPathContextPtr xpath_context(xmlXPathNewContext(
1396  pimpl_->xmlnode_->doc));
1397  if (!xpath_context) {
1398  const xmlError * last_error(xmlGetLastError());
1399  std::string message("cannot create xpath context");
1400 
1401  if (last_error && last_error->message)
1402  message += " : " + std::string(last_error->message);
1403 
1404  throw xml::exception(message);
1405  }
1406  const ns_list_type& nspaces(expr.get_namespaces());
1407  for (ns_list_type::const_iterator k(nspaces.begin());
1408  k!=nspaces.end(); ++k) {
1409  const char* prefix(k->get_prefix());
1410  if (strlen(prefix) == 0) {
1411  prefix = NULL;
1412  }
1413  if (xmlXPathRegisterNs(
1414  xpath_context,
1415  reinterpret_cast<const xmlChar*>(prefix),
1416  reinterpret_cast<const xmlChar*>(k->get_uri())) != 0) {
1417  const xmlError * last_error(xmlGetLastError());
1418  std::string message("cannot create xpath context "
1419  "(namespace registering error)");
1420 
1421  if (last_error && last_error->message)
1422  message += " : " + std::string(last_error->message);
1423 
1424  xmlXPathFreeContext(xpath_context);
1425  throw xml::exception(message);
1426  }
1427  }
1428  xpath_context->node = pimpl_->xmlnode_;
1429  return xpath_context;
1430 }
1431 
1432 
1433 void *
1435  void* context) const {
1436  xmlXPathObjectPtr object(NULL);
1437 
1439  object = xmlXPathCompiledEval(
1440  reinterpret_cast<xmlXPathCompExprPtr>(
1441  expr.get_compiled_expression()),
1442  reinterpret_cast<xmlXPathContextPtr>(context));
1443  }
1444  else {
1445  object = xmlXPathEvalExpression(
1446  reinterpret_cast<const xmlChar*>(expr.get_xpath()),
1447  reinterpret_cast<xmlXPathContextPtr>(context));
1448  }
1449  if (!object) {
1450  const xmlError * last_error(xmlGetLastError());
1451  std::string message("error evaluating xpath expression");
1452 
1453  if (last_error && last_error->message)
1454  message += " : " + std::string(last_error->message);
1455 
1456  xmlXPathFreeContext(reinterpret_cast<xmlXPathContextPtr>(context));
1457  throw xml::exception(message);
1458  }
1459  return object;
1460 }
1461 
1462 
1464  return iterator(xml::impl::node_insert(pimpl_->xmlnode_, 0,
1465  n.pimpl_->xmlnode_));
1466 }
1467 
1468 
1470  const node &n) {
1472  pimpl_->xmlnode_,
1473  static_cast<xmlNodePtr>(position.get_raw_node()),
1474  n.pimpl_->xmlnode_));
1475 }
1476 
1477 
1479 xml::node::replace (const iterator& old_node, const node &new_node) {
1481  static_cast<xmlNodePtr>(old_node.get_raw_node()),
1482  new_node.pimpl_->xmlnode_));
1483 }
1484 
1485 
1488  static_cast<xmlNodePtr>(to_erase.get_raw_node())));
1489 }
1490 
1491 
1493  while (first != last) first = erase(first);
1494  return first;
1495 }
1496 
1497 
1499  size_type removed_count(0);
1500  iterator to_remove(begin()), the_end(end());
1501 
1502  while ( (to_remove = find(name, to_remove)) != the_end) {
1503  ++removed_count;
1504  to_remove = erase(to_remove);
1505  }
1506 
1507  return removed_count;
1508 }
1509 
1510 
1511 void xml::node::clear (void) {
1512  if (!pimpl_->xmlnode_->children)
1513  return;
1514  xmlFreeNodeList(pimpl_->xmlnode_->children);
1515  pimpl_->xmlnode_->children = NULL;
1516  pimpl_->xmlnode_->last = NULL;
1517 }
1518 
1519 
1520 void xml::node::sort (const char *node_name, const char *attr_name) {
1521  xmlNodePtr i(pimpl_->xmlnode_->children), next(0);
1522  std::vector<xmlNodePtr> node_list;
1523 
1524  while (i!=0) {
1525  next = i->next;
1526 
1527  if (i->type == XML_ELEMENT_NODE &&
1528  xmlStrcmp(i->name,
1529  reinterpret_cast<const xmlChar*>(node_name)) == 0) {
1530  xmlUnlinkNode(i);
1531  node_list.push_back(i);
1532  }
1533 
1534  i = next;
1535  }
1536 
1537  if (node_list.empty()) return;
1538 
1539  std::sort(node_list.begin(), node_list.end(), compare_attr(attr_name));
1540  std::for_each(node_list.begin(), node_list.end(),
1541  insert_node(pimpl_->xmlnode_));
1542 }
1543 
1544 
1546  xmlNodePtr i(pimpl_->xmlnode_->children), next(0);
1547  std::vector<xmlNodePtr> node_list;
1548 
1549  while (i!=0) {
1550  next = i->next;
1551 
1552  if (i->type == XML_ELEMENT_NODE) {
1553  xmlUnlinkNode(i);
1554  node_list.push_back(i);
1555  }
1556 
1557  i = next;
1558  }
1559 
1560  if (node_list.empty()) return;
1561 
1562  std::sort(node_list.begin(), node_list.end(), node_cmp(cb));
1563  std::for_each(node_list.begin(), node_list.end(),
1564  insert_node(pimpl_->xmlnode_));
1565 }
1566 
1567 
1569  save_option_flags flags) const {
1570  int compression_level = flags & 0xFFFF;
1571  node2doc n2d(pimpl_->xmlnode_);
1572  xmlDocPtr doc = n2d.get_doc();
1573 
1574  // Compression level is currently not analyzed by libxml2
1575  // So this might work in the future implementations but is ignored now.
1576  doc->compression = compression_level;
1577 
1578  int libxml2_options = convert_to_libxml2_save_options(flags);
1579 
1580  const char * enc = NULL;
1581  if (pimpl_->xmlnode_->doc)
1582  enc = (const char *)(pimpl_->xmlnode_->doc->encoding);
1583 
1584  xmlSaveCtxtPtr ctxt = xmlSaveToIO(save_to_string_cb, NULL, &xml,
1585  enc, libxml2_options);
1586 
1587  if (ctxt) {
1588  xmlSaveDoc(ctxt, doc);
1589  xmlSaveClose(ctxt); // xmlSaveFlush() is called in xmlSaveClose()
1590  }
1591 }
1592 
1593 
1595  save_option_flags flags) const
1596 {
1597  xml.clear();
1598  append_to_string(xml, flags);
1599 }
1600 
1601 
1603  std::string & str,
1604  canonicalization_option c14n_option,
1605  canonicalization_comments_option comments_option,
1606  canonicalization_format_option format_option,
1607  canonicalization_node_sort_option node_sort_option) const
1608 {
1609  node2doc n2d(pimpl_->xmlnode_);
1610  xmlDocPtr raw_doc = n2d.get_doc();
1611 
1612  document doc;
1613  doc.set_doc_data(raw_doc);
1614 
1615  try {
1616  doc.save_to_string_canonical(str, c14n_option, comments_option,
1617  format_option, node_sort_option);
1618  } catch (...) {
1619  // Avoid double document destruction
1620  doc.release_doc_data();
1621  throw;
1622  }
1623 
1624  // Avoid double document destruction
1625  doc.release_doc_data();
1626 }
1627 
1628 
1629 node_set xml::node::convert_to_nset(void * object_as_void) const {
1630  // It converts a scalar xpath object into a nodeset with 1 node in it
1631  xmlXPathObjectPtr object = reinterpret_cast<xmlXPathObjectPtr>(
1632  object_as_void);
1634  std::string content;
1635 
1636  switch (object->type) {
1637  case XPATH_BOOLEAN:
1638  type_name = "boolean";
1639  if (object->boolval == 0) content = "false";
1640  else content = "true";
1641  break;
1642  case XPATH_NUMBER:
1643  type_name = "number";
1644  char buffer[64];
1645  snprintf(buffer, 64, "%g", object->floatval);
1646  content = std::string(buffer);
1647  break;
1648  case XPATH_STRING:
1649  type_name = "string";
1650  content = std::string(
1651  reinterpret_cast<const char*>(object->stringval));
1652  break;
1653  default:
1654  throw xml::exception("Internal logic error: unexpected xpath "
1655  "object type to be converted "
1656  "into a node set");
1657  }
1658 
1659  // Create a node
1660  xml::node new_node("xpath_scalar_result", content.c_str());
1661  new_node.get_attributes().insert("type", type_name.c_str());
1662 
1663  // Add node to a node set
1664  xmlNodeSetPtr new_node_set = xmlXPathNodeSetCreate(NULL);
1665  if (new_node_set == NULL)
1666  throw xml::exception("Cannot create node set while "
1667  "converting xpath result");
1668  xmlXPathNodeSetAdd(new_node_set,
1669  reinterpret_cast<xmlNodePtr>(new_node.get_node_data()));
1670  new_node.release_node_data();
1671 
1672  // Update the type
1673  object->type = XPATH_NODESET;
1674  object->nodesetval = new_node_set;
1675  object->boolval = 1; // Hack: to have the contained nodes deleted as well
1676 
1677  return node_set(object);
1678 }
1679 
1680 
1681 struct ns_cmp {
1682  bool operator() (const xmlNsPtr & lhs, const xmlNsPtr & rhs) const {
1683  if (lhs->prefix == NULL)
1684  return true;
1685  if (lhs->prefix[0] == '\0')
1686  return true;
1687  if (rhs->prefix == NULL)
1688  return false;
1689  if (rhs->prefix[0] == '\0')
1690  return false;
1691  return strcmp(reinterpret_cast<const char *>(lhs->prefix),
1692  reinterpret_cast<const char *>(rhs->prefix)) < 0;
1693  }
1694 };
1695 
1697 {
1698  std::list<xmlNsPtr> ns_defs;
1699  xmlNsPtr nsd = pimpl_->xmlnode_->nsDef;
1700 
1701  // Collect the pointers to the namespace definitions
1702  while (nsd != 0) {
1703  ns_defs.push_back(nsd);
1704  nsd = nsd->next;
1705  }
1706 
1707  // Sort pointers by the namespace prefixes
1708  ns_defs.sort(ns_cmp());
1709 
1710  // Modify the list of the namespace definitions
1711  xmlNsPtr cur = NULL;
1712  xmlNsPtr prev = NULL;
1713 
1714  for (std::list<xmlNsPtr>::const_iterator k = ns_defs.begin();
1715  k != ns_defs.end(); ++k) {
1716  cur = *k;
1717 
1718  if (prev == NULL)
1719  pimpl_->xmlnode_->nsDef = cur;
1720 
1721  cur->next = NULL;
1722 
1723  if (prev != NULL)
1724  prev->next = cur;
1725 
1726  prev = cur;
1727  }
1728 }
1729 
1730 
1731 
1732 namespace xml {
1733  std::ostream& operator<< (std::ostream &stream, const xml::node &n) {
1734  node2doc n2d(n.pimpl_->xmlnode_);
1735  xmlDocPtr doc = n2d.get_doc();
1736 
1737  int libxml2_options = convert_to_libxml2_save_options(save_op_default);
1738 
1739  const char * enc = NULL;
1740  if (n.pimpl_->xmlnode_->doc)
1741  enc = (const char *)(n.pimpl_->xmlnode_->doc->encoding);
1742 
1743  xmlSaveCtxtPtr ctxt = xmlSaveToIO(save_to_stream_cb, NULL, &stream,
1744  enc, libxml2_options);
1745 
1746  if (ctxt) {
1747  xmlSaveDoc(ctxt, doc);
1748  xmlSaveClose(ctxt); // xmlSaveFlush() is called in xmlSaveClose()
1749  }
1750  return stream;
1751  }
1752 }
This file defines the xml::ait_impl class.
This file contains the definition of the xml::attributes class.
Const Iterator class for accessing attribute pairs.
Definition: attributes.hpp:320
Iterator class for accessing attribute pairs.
Definition: attributes.hpp:285
The xml::attributes class is used to access all the attributes of one xml::node.
Definition: attributes.hpp:78
void insert(const char *name, const char *value, const ns *nspace=NULL)
Add an attribute to the attributes list.
Definition: attributes.cpp:188
The xml::document class is used to hold the XML tree and various bits of information about it.
Definition: document.hpp:80
void set_doc_data(void *data)
Definition: document.cpp:998
void * release_doc_data(void)
Definition: document.cpp:1028
void save_to_string_canonical(std::string &str, canonicalization_option c14n_option, canonicalization_comments_option comments_option, canonicalization_format_option format_option, canonicalization_node_sort_option node_sort_option) const
Convert the XML document tree into XML text data and place it into the given string.
Definition: document.cpp:810
This exception class is thrown by xmlwrapp for all runtime XML-related errors along with the xml::par...
Definition: exception.hpp:64
const char * get(void) const
Definition: utility.hpp:81
The xml::node::const_iterator provides a way to access children nodes similar to a standard C++ conta...
Definition: node.hpp:746
void * get_raw_node(void) const
The xml::node::iterator provides a way to access children nodes similar to a standard C++ container.
Definition: node.hpp:704
void * get_raw_node(void) const
The xml::node_set class is used to store xpath query result set.
Definition: node_set.hpp:68
The xml::node class is used to hold information about one XML node.
Definition: node.hpp:106
void set_name(const char *name)
Set the name of this xml::node.
Definition: node.cpp:764
node_set convert_to_nset(void *) const
Definition: node.cpp:1629
node_type get_type(void) const
Get this node's "type".
Definition: node.cpp:806
void * release_node_data(void)
Definition: node.cpp:758
void append_to_string(std::string &xml, save_option_flags flags=save_op_default) const
Convert the node and all its children into XML text and set the given string to that text.
Definition: node.cpp:1568
ns_definition_adding_type
enum for policies of adding namespace definitions
Definition: node.hpp:133
void erase_namespace(void)
Remove the node namespace.
Definition: node.cpp:1077
attributes::iterator find_attribute(const char *name, const ns *nspace=NULL)
Search for a node attribute.
Definition: node.cpp:851
bool is_text(void) const
Find out if this node is a text node or sometiming like a text node, CDATA for example.
Definition: node.cpp:1189
const char * get_name(void) const
Get the name of this xml::node.
Definition: node.cpp:769
ns_list_type get_namespace_definitions(ns::ns_safety_type type=ns::type_safe_ns) const
Get the namespaces defined at this xml::node.
Definition: node.cpp:876
effective_ns_list_type
enum to specify what namespaces to include into the list of the node effective namespaces
Definition: node.hpp:155
iterator erase(const iterator &to_erase)
Erase the node that is pointed to by the given iterator.
Definition: node.cpp:1486
void * evaluate_xpath_expression(const xml::xpath_expression &expr, void *context) const
Definition: node.cpp:1434
ns add_namespace_definition(const ns &name_space, ns_definition_adding_type type)
Add namespace definition to the node.
Definition: node.cpp:945
void clear(void)
Erase all children nodes.
Definition: node.cpp:1511
iterator parent(void)
Get an iterator that points at the parent of this node.
Definition: node.cpp:1244
void erase_unused_ns_defs(void)
Erase unused namespace definitions.
Definition: node.cpp:1151
void save_to_string_canonical(std::string &str, canonicalization_option c14n_option, canonicalization_comments_option comments_option, canonicalization_format_option format_option, canonicalization_node_sort_option node_sort_option) const
Convert the node and all its children into XML text and set the given string to that text.
Definition: node.cpp:1602
void set_node_data(void *data)
Definition: node.cpp:746
node & assign(const node &other)
Copy another node object into this one.
Definition: node.cpp:507
ns set_namespace(const ns &name_space)
Set the node namespace.
Definition: node.cpp:915
ns_definition_erase_type
enum to specify how to remove namespace definitions
Definition: node.hpp:139
ns_list_type get_effective_namespaces(effective_ns_list_type which=type_ns_all) const
Provides a list of effective namespaces for the node.
Definition: node.cpp:1354
node(void)
Construct a new blank xml::node.
Definition: node.cpp:401
bool empty(void) const
Find out if this node has any children.
Definition: node.cpp:1212
void push_back(const node &child)
Add a child xml::node to this node.
Definition: node.cpp:1194
iterator find(const char *name, const ns *nspace=NULL)
Find the first child node that has the given name and namespace.
Definition: node.cpp:1258
void erase_duplicate_ns_defs(void)
Erase duplicate namespace definitions.
Definition: node.cpp:1084
void * get_node_data(void) const
Definition: node.cpp:753
void erase_duplicate_ns_defs_single_node(void *nd, std::deque< ns_list_type > &defs)
Definition: node.cpp:1107
void * create_xpath_context(const xml::xpath_expression &expr) const
Definition: node.cpp:1390
node_type
enum for the different types of XML nodes
Definition: node.hpp:112
iterator replace(const iterator &old_node, const node &new_node)
Replace the node pointed to by the given iterator with another node.
Definition: node.cpp:1479
iterator begin(void)
Get an iterator that points to the beginning of this node's children.
Definition: node.cpp:1217
ns add_namespace_def(const char *uri, const char *prefix)
Definition: node.cpp:990
node * detached_copy(void) const
Create a copy of the node which is detached from the document.
Definition: node.cpp:521
std::string get_path(void) const
Get the node path.
Definition: node.cpp:1178
virtual ~node(void)
Class destructor.
Definition: node.cpp:740
void save_to_string(std::string &xml, save_option_flags flags=save_op_default) const
Convert the node and all its children into XML text and set the given string to that text.
Definition: node.cpp:1594
void set_content(const char *content)
Set the content of a node.
Definition: node.cpp:774
ns get_namespace(ns::ns_safety_type type=ns::type_safe_ns) const
Get the namespace of this xml::node.
Definition: node.cpp:863
node_set run_xpath_query(const xpath_expression &expr)
Run the given XPath query.
Definition: node.cpp:1292
void * find_replacement_ns_def(std::deque< ns_list_type > &defs, void *ns)
Definition: node.cpp:1128
void sort_namespace_definitions(void)
Sorts the namespace definitions in the node in place.
Definition: node.cpp:1696
node & operator=(const node &other)
Make this node equal to some other node via assignment.
Definition: node.cpp:514
const char * get_content(void) const
Get the content for this text node.
Definition: node.cpp:797
void erase_namespace_definition(const char *prefix, ns_definition_erase_type how=type_ns_def_erase_if_not_used)
Remove the node namespace definition.
Definition: node.cpp:1041
std::size_t size_type
size type
Definition: node.hpp:109
bool is_root(void) const
Find out if this node is a root one, i.e.
Definition: node.cpp:1237
void set_raw_content(const char *raw_content)
Set the raw content of a node.
Definition: node.cpp:791
void add_namespace_definitions(const ns_list_type &name_spaces, ns_definition_adding_type type)
Add namespace definitions to the node.
Definition: node.cpp:982
ns lookup_namespace(const char *prefix, ns::ns_safety_type type=ns::type_safe_ns) const
Look up a namespace with the given prefix.
Definition: node.cpp:1025
void swap(node &other)
Swap this node with another one.
Definition: node.cpp:551
impl::node_impl * pimpl_
Definition: node.hpp:1385
iterator insert(const node &n)
Insert a new child node.
Definition: node.cpp:1463
size_type size(void) const
Returns the number of childer this nodes has.
Definition: node.cpp:1199
void sort_fo(impl::cbfo_node_compare &fo)
Definition: node.cpp:1545
ns add_matched_namespace_def(void *libxml2RawNamespace, const char *uri, ns_definition_adding_type type)
Definition: node.cpp:1012
void sort(const char *node_name, const char *attr_name)
Sort all the children nodes of this node using one of thier attributes.
Definition: node.cpp:1520
iterator self(void)
Get an iterator that points back at this node.
Definition: node.cpp:1227
xml::attributes & get_attributes(void)
Get the list of attributes.
Definition: node.cpp:831
The xml::ns class is used to access and handle namespaces of nodes and attributes.
Definition: namespace.hpp:64
void * unsafe_ns_
Definition: namespace.hpp:196
ns_safety_type
Namespace object "safety".
Definition: namespace.hpp:67
@ type_safe_ns
Definition: namespace.hpp:68
@ type_unsafe_ns
Definition: namespace.hpp:69
const char * get_prefix(void) const
Get the namespace prefix.
Definition: namespace.cpp:95
const char * get_uri(void) const
Get the namespace URI.
Definition: namespace.cpp:109
bool is_safe(void) const
Check if the object is safe i.e.
Definition: namespace.cpp:154
ns(const char *prefix, const char *uri)
Create a new xml::ns object with the given prefix and URI.
Definition: namespace.cpp:59
bool is_void(void) const
If a node or an attribute has no namespace, then a namespace with empty prefix and empty URI is retur...
Definition: namespace.cpp:123
The xml::xpath_expression class is used to store xpath query string and optional XML namespaces.
void * get_compiled_expression() const
const char * get_xpath() const
Provide the xpath expression as a string.
const ns_list_type & get_namespaces() const
Provide the list of the registered XML namespaces.
compile_type get_compile_type() const
Provide the expression pre-compilation flag.
static uch flags
static xmlXPathObjectPtr evaluate_xpath_expression(xsltTransformContextPtr ctxt, const char *xpath_expression, xmlNodePtr node)
#define true
Definition: bool.h:35
static DLIST_TYPE *DLIST_NAME() first(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:46
static DLIST_TYPE *DLIST_NAME() last(DLIST_LIST_TYPE *list)
Definition: dlist.tmpl.h:51
static DLIST_TYPE *DLIST_NAME() prev(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:61
static DLIST_TYPE *DLIST_NAME() next(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:56
static const char * str(char *buf, int n)
Definition: stats.c:84
char data[12]
Definition: iconv.c:80
void swap(NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair1, NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair2)
Definition: ncbimisc.hpp:1508
string
Definition: cgiapp.hpp:690
#define NULL
Definition: ncbistd.hpp:225
int i
yy_size_t n
This file contains the definition of the xml::document class.
This file contains the definition of the xml::exception class.
This file contains the definition of the xml::node class.
constexpr auto sort(_Init &&init)
int strcmp(const char *str1, const char *str2)
Definition: odbc_utils.hpp:160
xmlNodePtr node_replace(xmlNodePtr old_node, xmlNodePtr new_node)
Replace a node with another one.
Definition: node_manip.cpp:75
void erase_ns_definition(xmlNodePtr node, xmlNsPtr definition)
Erases namespace definition in the node.
Definition: node_manip.cpp:170
xmlNsPtr lookup_default_ns_above(xmlNodePtr node)
Searches for a default namspace definition in the given node and above.
Definition: node_manip.cpp:198
xmlNodePtr node_erase(xmlNodePtr to_erase)
Erase a node from the child list, and then free it from memory.
Definition: node_manip.cpp:108
void update_children_default_ns(xmlNodePtr node, xmlNsPtr newns)
Replaces the node and its children default namespace with the given.
Definition: node_manip.cpp:157
int save_to_string_cb(void *ctx, const char *buf, int len)
Definition: utility.cpp:183
bool is_ns_used(xmlNodePtr node, xmlNsPtr ns)
Check if the node, attributes and children use the namespace.
Definition: node_manip.cpp:139
void replace_ns(xmlNodePtr node, xmlNsPtr oldNs, xmlNsPtr newNs)
Replaces old namspace with a new one in nodes and attributes all the way down in the hierarchy.
Definition: node_manip.cpp:211
int convert_to_libxml2_save_options(int options)
Definition: utility.cpp:142
phantom_attr * find_default_prop(xmlNodePtr xmlnode, const char *name, const ns *nspace)
Definition: ait_impl.cpp:567
xmlAttrPtr find_prop(xmlNodePtr xmlnode, const char *name, const ns *nspace)
Definition: ait_impl.cpp:512
int save_to_stream_cb(void *ctx, const char *buf, int len)
Definition: utility.cpp:177
xmlNodePtr node_insert(xmlNodePtr parent, xmlNodePtr before, xmlNodePtr to_add)
Insert a node somewhere in the child list of a parent node.
Definition: node_manip.cpp:54
xmlNsPtr lookup_ns_definition(xmlNodePtr node, const char *prefix)
Searches for a namspace definition in the given node.
Definition: node_manip.cpp:185
void invalidate_default_attr_iterators(xmlNodePtr xmlnode)
Definition: deref_impl.cpp:141
node_private_data * attach_node_private_data(void *)
Definition: deref_impl.cpp:95
XML library namespace.
Definition: attributes.hpp:57
int save_option_flags
Bitwise save options mask type and a compression level.
Definition: xml_save.hpp:78
std::ostream & operator<<(std::ostream &stream, const document &doc)
Definition: document.cpp:1035
std::vector< xml::ns > ns_list_type
type for holding XML namespaces
Definition: namespace.hpp:208
canonicalization_comments_option
Definition: xml_save.hpp:103
@ save_op_default
Default is:
Definition: xml_save.hpp:72
canonicalization_option
Canonicalization mode.
Definition: xml_save.hpp:83
canonicalization_format_option
Definition: xml_save.hpp:108
canonicalization_node_sort_option
Definition: xml_save.hpp:113
Front end for a platform-specific configuration summary.
This file defines the xml::impl::node_iterator class for libxml2.
This file contains the definition of the xml::node manipulation functions.
XPath execution result set for XmlWrapp.
static uint8_t * buffer
Definition: pcre2test.c:1016
Definition: type.c:6
bool operator()(xmlNodePtr lhs, xmlNodePtr rhs)
Definition: node.cpp:111
node_cmp(cbfo_node_compare &cb)
Definition: node.cpp:109
cbfo_node_compare & cb_
Definition: node.cpp:119
xmlNodePtr xmlnode_
Definition: node.cpp:99
attributes attrs_
Definition: node.cpp:101
void release(void)
Definition: node.cpp:92
std::string tmp_string
Definition: node.cpp:102
struct attr_instance * attr_instances_
Definition: deref_impl.hpp:89
struct phantom_attr * phantom_attrs_
Definition: deref_impl.hpp:88
static bool node_ns_match(xmlNode *nd, const ns *nspace)
Definition: utility.cpp:94
Helper struct for creating a xml::node of type_cdata.
Definition: node.hpp:168
const char * t
Definition: node.hpp:170
Helper struct for creating a xml::node of type_comment.
Definition: node.hpp:180
const char * t
Definition: node.hpp:182
Helper struct for creating a xml::node of type_pi.
Definition: node.hpp:192
const char * n
Definition: node.hpp:194
const char * c
Definition: node.hpp:194
Helper struct for creating a xml::node of type_text.
Definition: node.hpp:204
const char * t
Definition: node.hpp:206
static const char * type_name(CS_INT value)
Definition: will_convert.c:122
static CS_CONTEXT * context
Definition: will_convert.c:21
Modified on Fri Sep 20 14:57:31 2024 by modify_doxy.py rev. 669887