NCBI C++ ToolKit
node_manip.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  * All Rights Reserved
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name of the Author nor the names of its contributors
16  * may be used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
23  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*
34  * $Id: node_manip.cpp 97995 2022-09-16 13:18:35Z satskyse $
35  * NOTE: This file was modified from its original version 0.6.0
36  * to fit the NCBI C++ Toolkit build framework and
37  * API and functionality requirements.
38  * Most importantly, it adds support for XML namespaces (see "namespace.hpp").
39  */
40 
41 /** @file
42  * This file contains the implementation of the xml::node manipulation
43  * functions.
44 **/
45 
46 // xmlwrapp includes
48 #include "node_manip.hpp"
49 
50 // libxml includes
51 #include <libxml/tree.h>
52 
53 //####################################################################
54 xmlNodePtr xml::impl::node_insert (xmlNodePtr parent, xmlNodePtr before, xmlNodePtr to_add) {
55  xmlNodePtr new_xml_node = xmlCopyNode(to_add, 1);
56  if (!new_xml_node) throw std::bad_alloc();
57 
58  if (before == 0) { // insert at the end of the child list
59  if (xmlAddChild(parent, new_xml_node) == 0) {
60  xmlFreeNode(new_xml_node);
61  throw xml::exception("failed to insert xml::node; xmlAddChild failed");
62  }
63  } else {
64  if (xmlAddPrevSibling(before, new_xml_node) == 0) {
65  xmlFreeNode(new_xml_node);
66  throw xml::exception("failed to insert xml::node; xmlAddPrevSibling failed");
67  }
68  }
69  if (!new_xml_node->ns) new_xml_node->ns = xmlSearchNs(NULL, parent, NULL);
70  if (new_xml_node->ns) set_children_default_ns(new_xml_node, new_xml_node->ns);
71 
72  return new_xml_node;
73 }
74 //####################################################################
75 xmlNodePtr xml::impl::node_replace (xmlNodePtr old_node, xmlNodePtr new_node) {
76  xmlNodePtr copied_node = xmlCopyNode(new_node, 1);
77  if (!copied_node) throw std::bad_alloc();
78 
79  // Note: the libxml2 xmlReplaceNode(...) does not tell if it completed successfully.
80  // The hack is to set a pointer to a document to a certain value. If the pointer
81  // is changed then the replacement succseeded. Below a temporary empty document
82  // is created for that purpose.
83  xmlDocPtr temp_to_test_replace_success = xmlNewDoc((const xmlChar *)("1.0"));
84  if (!temp_to_test_replace_success) {
85  xmlFreeNode(copied_node);
86  throw std::bad_alloc();
87  }
88 
89  // hack to see if xmlReplaceNode was successful
90  copied_node->doc = temp_to_test_replace_success;
91  xmlReplaceNode(old_node, copied_node);
92 
93  if (copied_node->doc == temp_to_test_replace_success) {
94  xmlFreeDoc(temp_to_test_replace_success);
95  xmlFreeNode(copied_node);
96  throw xml::exception("failed to replace xml::node; xmlReplaceNode() failed");
97  }
98 
99  xmlFreeDoc(temp_to_test_replace_success);
100  xmlFreeNode(old_node);
101 
102  if (!copied_node->ns) copied_node->ns = xmlSearchNs(NULL, copied_node->parent, NULL);
103  if (copied_node->ns) set_children_default_ns(copied_node, copied_node->ns);
104 
105  return copied_node;
106 }
107 //####################################################################
108 xmlNodePtr xml::impl::node_erase (xmlNodePtr to_erase) {
109  xmlNodePtr after = to_erase->next;
110 
111  xmlUnlinkNode(to_erase);
112  xmlFreeNode(to_erase);
113 
114  return after;
115 }
116 //####################################################################
117 void xml::impl::set_children_default_ns (xmlNodePtr node, xmlNsPtr default_ns) {
118  if (!node->ns) node->ns = default_ns;
119  node = node->children;
120  while (node) {
122  set_children_default_ns(node, default_ns);
123  if (!node->ns) node->ns = default_ns;
124  }
125  node = node->next;
126  }
127 }
128 //####################################################################
130  if (!node ||!node->nsDef) return false;
131  xmlNs * current(node->nsDef);
132  while (current) {
133  if (!current->prefix) return true;
134  current = current->next;
135  }
136  return false;
137 }
138 //####################################################################
139 bool xml::impl::is_ns_used (xmlNodePtr node, xmlNsPtr ns) {
140  if (!node) return false;
141 
142  // Does the node itself use namespace
143  if (node->ns == ns) return true;
144 
145  // Do the node attributes use namespace
146  for (xmlAttrPtr current = node->properties; current; current = current->next)
147  if (current->ns == ns) return true;
148 
149  node = node->children;
150  while (node) {
151  if (is_ns_used(node, ns)) return true;
152  node = node->next;
153  }
154  return false;
155 }
156 //####################################################################
157 void xml::impl::update_children_default_ns (xmlNodePtr node, xmlNsPtr newns) {
158  if (!node) return;
159  node = node->children;
160  while (node) {
163  if (!node->ns || !node->ns->prefix)
164  node->ns = newns;
165  }
166  node = node->next;
167  }
168 }
169 //####################################################################
170 void xml::impl::erase_ns_definition (xmlNodePtr node, xmlNsPtr definition) {
171  if (!node->nsDef) return;
172  if (node->nsDef != definition) {
173  xmlNs *prev(node->nsDef);
174  while (prev && prev->next != definition)
175  prev = prev->next;
176  if (!prev) return;
177  prev->next = definition->next;
178  }
179  else {
180  node->nsDef = definition->next;
181  }
182  xmlFreeNs(definition);
183 }
184 //####################################################################
185 xmlNsPtr xml::impl::lookup_ns_definition (xmlNodePtr node, const char *prefix) {
186  xmlNs *current(node->nsDef);
187  while (current) {
188  if (!prefix && !current->prefix) return current;
189  if (prefix && current->prefix) {
190  if (xmlStrEqual(reinterpret_cast<const xmlChar*>(prefix), current->prefix))
191  return current;
192  }
193  current = current->next;
194  }
195  return NULL;
196 }
197 //####################################################################
199  if (!node)
200  return NULL;
201 
202  xmlNs *current(node->nsDef);
203  while (current) {
204  if (!current->prefix)
205  return current;
206  current = current->next;
207  }
209 }
210 //####################################################################
211 void xml::impl::replace_ns (xmlNodePtr node, xmlNsPtr oldNs, xmlNsPtr newNs) {
212  if (!node) return;
213 
214  // Does the node itself use namespace
215  if (node->ns == oldNs) node->ns = newNs;
216 
217  // Do the node attributes use namespace
218  for (xmlAttrPtr current = node->properties; current; current = current->next)
219  if (current->ns == oldNs) {
220  // Attributes may not have a default namspace
221  if (newNs && newNs->prefix)
222  current->ns = newNs;
223  else
224  current->ns = NULL;
225  }
226 
227  node = node->children;
228  while (node) {
229  replace_ns(node, oldNs, newNs);
230  node = node->next;
231  }
232 }
233 //####################################################################
234 
This exception class is thrown by xmlwrapp for all runtime XML-related errors along with the xml::par...
Definition: exception.hpp:64
The xml::node class is used to hold information about one XML node.
Definition: node.hpp:106
iterator parent(void)
Get an iterator that points at the parent of this node.
Definition: node.cpp:1244
The xml::ns class is used to access and handle namespaces of nodes and attributes.
Definition: namespace.hpp:64
static DLIST_TYPE *DLIST_NAME() prev(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:61
#define NULL
Definition: ncbistd.hpp:225
This file contains the definition of the xml::exception class.
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 set_children_default_ns(xmlNodePtr node, xmlNsPtr default_ns)
Set the node and its children default namespace to the given.
Definition: node_manip.cpp:117
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
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
bool has_default_ns_definition(xmlNodePtr node)
Check if the node holds default namespace definition.
Definition: node_manip.cpp:129
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
This file contains the definition of the xml::node manipulation functions.
static const char * prefix[]
Definition: pcregrep.c:405
Modified on Sun Feb 25 03:02:04 2024 by modify_doxy.py rev. 669887