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 430203 2014-03-24 18:01:17Z 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
47 #include <misc/xmlwrapp/exception.hpp>
48 #include "node_manip.hpp"
49
50 // libxml includes
51 #include <libxml/tree.h>
52
53 //####################################################################
node_insert(xmlNodePtr parent,xmlNodePtr before,xmlNodePtr to_add)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 //####################################################################
node_replace(xmlNodePtr old_node,xmlNodePtr new_node)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 // hack to see if xmlReplaceNode was successful
80 copied_node->doc = reinterpret_cast<xmlDocPtr>(old_node);
81 xmlReplaceNode(old_node, copied_node);
82
83 if (copied_node->doc == reinterpret_cast<xmlDocPtr>(old_node)) {
84 xmlFreeNode(copied_node);
85 throw xml::exception("failed to replace xml::node; xmlReplaceNode() failed");
86 }
87
88 xmlFreeNode(old_node);
89
90 if (!copied_node->ns) copied_node->ns = xmlSearchNs(NULL, copied_node->parent, NULL);
91 if (copied_node->ns) set_children_default_ns(copied_node, copied_node->ns);
92
93 return copied_node;
94 }
95 //####################################################################
node_erase(xmlNodePtr to_erase)96 xmlNodePtr xml::impl::node_erase (xmlNodePtr to_erase) {
97 xmlNodePtr after = to_erase->next;
98
99 xmlUnlinkNode(to_erase);
100 xmlFreeNode(to_erase);
101
102 return after;
103 }
104 //####################################################################
set_children_default_ns(xmlNodePtr node,xmlNsPtr default_ns)105 void xml::impl::set_children_default_ns (xmlNodePtr node, xmlNsPtr default_ns) {
106 if (!node->ns) node->ns = default_ns;
107 node = node->children;
108 while (node) {
109 if (!has_default_ns_definition(node)) {
110 set_children_default_ns(node, default_ns);
111 if (!node->ns) node->ns = default_ns;
112 }
113 node = node->next;
114 }
115 }
116 //####################################################################
has_default_ns_definition(xmlNodePtr node)117 bool xml::impl::has_default_ns_definition (xmlNodePtr node) {
118 if (!node ||!node->nsDef) return false;
119 xmlNs * current(node->nsDef);
120 while (current) {
121 if (!current->prefix) return true;
122 current = current->next;
123 }
124 return false;
125 }
126 //####################################################################
is_ns_used(xmlNodePtr node,xmlNsPtr ns)127 bool xml::impl::is_ns_used (xmlNodePtr node, xmlNsPtr ns) {
128 if (!node) return false;
129
130 // Does the node itself use namespace
131 if (node->ns == ns) return true;
132
133 // Do the node attributes use namespace
134 for (xmlAttrPtr current = node->properties; current; current = current->next)
135 if (current->ns == ns) return true;
136
137 node = node->children;
138 while (node) {
139 if (is_ns_used(node, ns)) return true;
140 node = node->next;
141 }
142 return false;
143 }
144 //####################################################################
update_children_default_ns(xmlNodePtr node,xmlNsPtr newns)145 void xml::impl::update_children_default_ns (xmlNodePtr node, xmlNsPtr newns) {
146 if (!node) return;
147 node = node->children;
148 while (node) {
149 if (!has_default_ns_definition(node)) {
150 update_children_default_ns(node, newns);
151 if (!node->ns || !node->ns->prefix)
152 node->ns = newns;
153 }
154 node = node->next;
155 }
156 }
157 //####################################################################
erase_ns_definition(xmlNodePtr node,xmlNsPtr definition)158 void xml::impl::erase_ns_definition (xmlNodePtr node, xmlNsPtr definition) {
159 if (!node->nsDef) return;
160 if (node->nsDef != definition) {
161 xmlNs *prev(node->nsDef);
162 while (prev && prev->next != definition)
163 prev = prev->next;
164 if (!prev) return;
165 prev->next = definition->next;
166 }
167 else {
168 node->nsDef = definition->next;
169 }
170 xmlFreeNs(definition);
171 }
172 //####################################################################
lookup_ns_definition(xmlNodePtr node,const char * prefix)173 xmlNsPtr xml::impl::lookup_ns_definition (xmlNodePtr node, const char *prefix) {
174 xmlNs *current(node->nsDef);
175 while (current) {
176 if (!prefix && !current->prefix) return current;
177 if (prefix && current->prefix) {
178 if (xmlStrEqual(reinterpret_cast<const xmlChar*>(prefix), current->prefix))
179 return current;
180 }
181 current = current->next;
182 }
183 return NULL;
184 }
185 //####################################################################
lookup_default_ns_above(xmlNodePtr node)186 xmlNsPtr xml::impl::lookup_default_ns_above (xmlNodePtr node) {
187 if (!node)
188 return NULL;
189
190 xmlNs *current(node->nsDef);
191 while (current) {
192 if (!current->prefix)
193 return current;
194 current = current->next;
195 }
196 return lookup_default_ns_above(node->parent);
197 }
198 //####################################################################
replace_ns(xmlNodePtr node,xmlNsPtr oldNs,xmlNsPtr newNs)199 void xml::impl::replace_ns (xmlNodePtr node, xmlNsPtr oldNs, xmlNsPtr newNs) {
200 if (!node) return;
201
202 // Does the node itself use namespace
203 if (node->ns == oldNs) node->ns = newNs;
204
205 // Do the node attributes use namespace
206 for (xmlAttrPtr current = node->properties; current; current = current->next)
207 if (current->ns == oldNs) {
208 // Attributes may not have a default namspace
209 if (newNs && newNs->prefix)
210 current->ns = newNs;
211 else
212 current->ns = NULL;
213 }
214
215 node = node->children;
216 while (node) {
217 replace_ns(node, oldNs, newNs);
218 node = node->next;
219 }
220 }
221 //####################################################################
222
223