Skip to content

Commit fb20606

Browse files
author
Kjell Ahlstedt
committed
Move add_child() methods from Node to Element
* libxml++/nodes/element.[h|cc]: * libxml++/nodes/node.[h|cc]: Move all add_child*() methods to Element and rename them to add_child_element*(). * examples/dom_build/main.cc: * examples/dom_update_namespace/main.cc: * examples/dtdvalidation/main.cc: * examples/sax_parser_build_dom/svgparser.cc: Change add_child() to add_child_element(). Bug #754673.
1 parent a82fb4d commit fb20606

File tree

8 files changed

+250
-267
lines changed

8 files changed

+250
-267
lines changed

examples/dom_build/main.cc

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// -*- C++ -*-
2-
31
/* main.cc
42
*
53
* Copyright (C) 2002 The libxml++ development team
@@ -48,7 +46,7 @@ main(int /* argc */, char** /* argv */)
4846
nodeRoot->set_namespace_declaration("http://foobar", "foobar"); //Also associate this prefix with this namespace:
4947

5048
nodeRoot->set_child_text("\n");
51-
auto nodeChild = nodeRoot->add_child("examplechild");
49+
auto nodeChild = nodeRoot->add_child_element("examplechild");
5250

5351
//Associate prefix with namespace:
5452
nodeChild->set_namespace_declaration("http://bar", "bar");
@@ -62,9 +60,9 @@ main(int /* argc */, char** /* argv */)
6260
nodeChild->add_child_text("\n");
6361
nodeChild->add_child_processing_instruction("application1", "This is an example node");
6462
nodeChild->add_child_text("\n");
65-
nodeChild->add_child("child_of_child", "bar");
63+
nodeChild->add_child_element("child_of_child", "bar");
6664

67-
nodeChild = nodeRoot->add_child("examplechild", "foobar"); //foobar is the namespace prefix
65+
nodeChild = nodeRoot->add_child_element("examplechild", "foobar"); //foobar is the namespace prefix
6866
nodeChild->set_attribute("id", "2", "foobar"); //foobar is the namespace prefix.
6967

7068
auto whole = document.write_to_string();
@@ -79,4 +77,3 @@ main(int /* argc */, char** /* argv */)
7977

8078
return EXIT_SUCCESS;
8179
}
82-

examples/dom_update_namespace/main.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ void TestNamespace::test_create_new_node_with_default_namespace()
100100
"Input file shouldn't have any child in alternate default namespace");
101101

102102
// Add child nodes in default namespace and check document again
103-
auto child = root_->add_child("child");
103+
auto child = root_->add_child_element("child");
104104
child->set_namespace_declaration(nsmap_["ns1"], "");
105105
root_->add_child_text("\n");
106-
root_->add_child_with_new_ns("child", nsmap_["ns1"]);
106+
root_->add_child_element_with_new_ns("child", nsmap_["ns1"]);
107107
root_->add_child_text("\n");
108108

109109
std::cout << " File " << filename << " after modification" << std::endl
@@ -128,12 +128,12 @@ void TestNamespace::test_create_new_node_using_existing_namespace_prefix()
128128
"Input file shouldn't have any child in child namespace");
129129

130130
// Add child nodes with specific namespace and check document again
131-
auto child = root_->add_child("child", "ns0");
131+
auto child = root_->add_child_element("child", "ns0");
132132
child->set_namespace_declaration(nsmap_["ns1"], "");
133133
root_->add_child_text("\n");
134-
root_->add_child_with_new_ns("child", nsmap_["ns1"]);
134+
root_->add_child_element_with_new_ns("child", nsmap_["ns1"]);
135135
root_->add_child_text("\n");
136-
root_->add_child_with_new_ns("child", nsmap_["ns1"], "ns3");
136+
root_->add_child_element_with_new_ns("child", nsmap_["ns1"], "ns3");
137137
root_->add_child_text("\n");
138138

139139
std::cout << " File " << filename << " after modification" << std::endl

examples/dtdvalidation/main.cc

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// -*- C++ -*-
2-
31
/* main.cc
42
*
53
* Copyright (C) 2002 The libxml++ development team
@@ -61,9 +59,9 @@ int main(int argc, char* argv[])
6159
}
6260

6361
/* auto nodeRoot2 = */document.create_root_node("example");
64-
auto child = document.get_root_node()->add_child("examplechild");
62+
auto child = document.get_root_node()->add_child_element("examplechild");
6563
child->set_attribute("id", "an_id");
66-
child->add_child("child_of_child");
64+
child->add_child_element("child_of_child");
6765

6866
try
6967
{
@@ -85,4 +83,3 @@ int main(int argc, char* argv[])
8583
}
8684
return return_code;
8785
}
88-

examples/sax_parser_build_dom/svgparser.cc

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
// -*- C++ -*-
2-
31
/* svgparser.cc
42
*
53
* By Dan Dennedy <dan@dennedy.org>
@@ -69,7 +67,7 @@ void Parser::on_start_element(const Glib::ustring& name,
6967
else
7068
{
7169
// Create the other elements as child nodes of the last nodes:
72-
element_normal = m_context.top()->add_child(elementName);
70+
element_normal = m_context.top()->add_child_element(elementName);
7371
}
7472

7573
// TODO: The following is a hack because it leverages knowledge of libxml++

libxml++/nodes/element.cc

Lines changed: 133 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,22 @@
1010

1111
#include <libxml/tree.h>
1212

13+
namespace // anonymous
14+
{
15+
// Common part of all add_child_element*() methods.
16+
xmlpp::Element* add_child_element_common(const Glib::ustring& name, xmlNode* child, xmlNode* node)
17+
{
18+
if (!node)
19+
{
20+
xmlFreeNode(child);
21+
throw xmlpp::internal_error("Could not add child element node " + name);
22+
}
23+
xmlpp::Node::create_wrapper(node);
24+
return static_cast<xmlpp::Element*>(node->_private);
25+
}
26+
27+
} // anonymous namespace
28+
1329
namespace xmlpp
1430
{
1531

@@ -128,6 +144,123 @@ void Element::remove_attribute(const Glib::ustring& name, const Glib::ustring& n
128144
}
129145
}
130146

147+
Element* Element::add_child_element(const Glib::ustring& name,
148+
const Glib::ustring& ns_prefix)
149+
{
150+
auto child = create_new_child_element_node(name, ns_prefix);
151+
auto node = xmlAddChild(cobj(), child);
152+
return add_child_element_common(name, child, node);
153+
}
154+
155+
Element* Element::add_child_element(xmlpp::Node* previous_sibling,
156+
const Glib::ustring& name, const Glib::ustring& ns_prefix)
157+
{
158+
if (!previous_sibling)
159+
return 0;
160+
161+
auto child = create_new_child_element_node(name, ns_prefix);
162+
auto node = xmlAddNextSibling(previous_sibling->cobj(), child);
163+
return add_child_element_common(name, child, node);
164+
}
165+
166+
Element* Element::add_child_element_before(xmlpp::Node* next_sibling,
167+
const Glib::ustring& name, const Glib::ustring& ns_prefix)
168+
{
169+
if (!next_sibling)
170+
return 0;
171+
172+
auto child = create_new_child_element_node(name, ns_prefix);
173+
auto node = xmlAddPrevSibling(next_sibling->cobj(), child);
174+
return add_child_element_common(name, child, node);
175+
}
176+
177+
Element* Element::add_child_element_with_new_ns(const Glib::ustring& name,
178+
const Glib::ustring& ns_uri, const Glib::ustring& ns_prefix)
179+
{
180+
auto child = create_new_child_element_node_with_new_ns(name, ns_uri, ns_prefix);
181+
auto node = xmlAddChild(cobj(), child);
182+
return add_child_element_common(name, child, node);
183+
}
184+
185+
Element* Element::add_child_element_with_new_ns(xmlpp::Node* previous_sibling,
186+
const Glib::ustring& name,
187+
const Glib::ustring& ns_uri, const Glib::ustring& ns_prefix)
188+
{
189+
if (!previous_sibling)
190+
return 0;
191+
192+
auto child = create_new_child_element_node_with_new_ns(name, ns_uri, ns_prefix);
193+
auto node = xmlAddNextSibling(previous_sibling->cobj(), child);
194+
return add_child_element_common(name, child, node);
195+
}
196+
197+
Element* Element::add_child_element_before_with_new_ns(xmlpp::Node* next_sibling,
198+
const Glib::ustring& name,
199+
const Glib::ustring& ns_uri, const Glib::ustring& ns_prefix)
200+
{
201+
if (!next_sibling)
202+
return 0;
203+
204+
auto child = create_new_child_element_node_with_new_ns(name, ns_uri, ns_prefix);
205+
auto node = xmlAddPrevSibling(next_sibling->cobj(), child);
206+
return add_child_element_common(name, child, node);
207+
}
208+
209+
_xmlNode* Element::create_new_child_element_node(const Glib::ustring& name,
210+
const Glib::ustring& ns_prefix)
211+
{
212+
xmlNs* ns = nullptr;
213+
214+
if (cobj()->type != XML_ELEMENT_NODE)
215+
throw internal_error("You can only add child nodes to element nodes");
216+
217+
if (ns_prefix.empty())
218+
{
219+
//Retrieve default namespace if it exists
220+
ns = xmlSearchNs(cobj()->doc, cobj(), 0);
221+
}
222+
else
223+
{
224+
//Use the existing namespace if one exists:
225+
ns = xmlSearchNs(cobj()->doc, cobj(), (const xmlChar*)ns_prefix.c_str());
226+
if (!ns)
227+
throw exception("The namespace prefix (" + ns_prefix + ") has not been declared.");
228+
}
229+
230+
return xmlNewNode(ns, (const xmlChar*)name.c_str());
231+
}
232+
233+
_xmlNode* Element::create_new_child_element_node_with_new_ns(const Glib::ustring& name,
234+
const Glib::ustring& ns_uri, const Glib::ustring& ns_prefix)
235+
{
236+
if (cobj()->type != XML_ELEMENT_NODE)
237+
throw internal_error("You can only add child nodes to element nodes.");
238+
239+
auto child = xmlNewNode(0, (const xmlChar*)name.c_str());
240+
if (!child)
241+
throw internal_error("Could not create new element node.");
242+
243+
auto ns = xmlNewNs(child, (const xmlChar*)(ns_uri.empty() ? 0 : ns_uri.c_str()),
244+
(const xmlChar*)(ns_prefix.empty() ? 0 : ns_prefix.c_str()) );
245+
// xmlNewNs() does not create a namespace node for the predefined xml prefix.
246+
// It's usually defined in the document and not in any specific node.
247+
if (!ns && ns_prefix == "xml")
248+
{
249+
ns = xmlSearchNs(cobj()->doc, cobj(), (const xmlChar*)ns_prefix.c_str());
250+
if (ns && (ns_uri != (ns->href ? (const char*)ns->href : "")))
251+
ns = nullptr;
252+
}
253+
if (!ns)
254+
{
255+
xmlFreeNode(child);
256+
throw internal_error("Could not create new namespace node.");
257+
}
258+
259+
xmlSetNs(child, ns);
260+
261+
return child;
262+
}
263+
131264
const TextNode* Element::get_child_text() const
132265
{
133266
// FIXME: return only the first content node
@@ -272,7 +405,6 @@ Glib::ustring Element::get_namespace_uri_for_prefix(const Glib::ustring& ns_pref
272405
return result;
273406
}
274407

275-
276408
CommentNode* Element::add_child_comment(const Glib::ustring& content)
277409
{
278410
auto child = xmlNewComment((const xmlChar*)content.c_str());
@@ -288,7 +420,6 @@ CommentNode* Element::add_child_comment(const Glib::ustring& content)
288420
return static_cast<CommentNode*>(node->_private);
289421
}
290422

291-
292423
CdataNode* Element::add_child_cdata(const Glib::ustring& content)
293424
{
294425
auto child = xmlNewCDataBlock(cobj()->doc, (const xmlChar*)content.c_str(), content.bytes());

libxml++/nodes/element.h

Lines changed: 106 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,15 +108,110 @@ class Element : public Node
108108
void remove_attribute(const Glib::ustring& name,
109109
const Glib::ustring& ns_prefix = Glib::ustring());
110110

111+
/** Add a child element to this node.
112+
*
113+
* @newin{3,0} Replaces Node::add_child()
114+
*
115+
* @param name The new node name
116+
* @param ns_prefix The namespace prefix. If the prefix has not been declared then this method will throw an exception.
117+
* @returns The newly-created element
118+
* @throws xmlpp::exception If a namespace prefix is specified, but has not been declared.
119+
* @throws xmlpp::internal_error If this node is not an element node,
120+
* or the child node cannot be created.
121+
*/
122+
Element* add_child_element(const Glib::ustring& name,
123+
const Glib::ustring& ns_prefix = Glib::ustring());
124+
125+
/** Add a child element to this node after the specified existing child node.
126+
*
127+
* @newin{3,0} Replaces Node::add_child()
128+
*
129+
* @param previous_sibling An existing child node.
130+
* @param name The new node name
131+
* @param ns_prefix The namespace prefix. If the prefix has not been declared then this method will throw an exception.
132+
* @returns The newly-created element
133+
* @throws xmlpp::exception If a namespace prefix is specified, but has not been declared.
134+
* @throws xmlpp::internal_error If this node is not an element node,
135+
* or the child node cannot be created.
136+
*/
137+
Element* add_child_element(xmlpp::Node* previous_sibling, const Glib::ustring& name,
138+
const Glib::ustring& ns_prefix = Glib::ustring());
139+
140+
/** Add a child element to this node before the specified existing child node.
141+
*
142+
* @newin{3,0} Replaces Node::add_child_before()
143+
*
144+
* @param next_sibling An existing child node.
145+
* @param name The new node name
146+
* @param ns_prefix The namespace prefix. If the prefix has not been declared then this method will throw an exception.
147+
* @returns The newly-created element
148+
* @throws xmlpp::exception If a namespace prefix is specified, but has not been declared.
149+
* @throws xmlpp::internal_error If this node is not an element node,
150+
* or the child node cannot be created.
151+
*/
152+
Element* add_child_element_before(xmlpp::Node* next_sibling, const Glib::ustring& name,
153+
const Glib::ustring& ns_prefix = Glib::ustring());
154+
155+
/** Add a child element to this node.
156+
*
157+
* @newin{3,0} Replaces Node::add_child_with_new_ns()
158+
*
159+
* @param name The new node name.
160+
* @param ns_uri The namespace to associate with the prefix,
161+
* or to use as the default namespace if no prefix is specified.
162+
* @param ns_prefix The prefix of the node's namespace. If no prefix is specified
163+
* then the namespace URI will be the default namespace.
164+
* @returns The newly-created element.
165+
* @throws xmlpp::internal_error If this node is not an element node,
166+
* or the child node or the namespace node cannot be created.
167+
*/
168+
Element* add_child_element_with_new_ns(const Glib::ustring& name,
169+
const Glib::ustring& ns_uri, const Glib::ustring& ns_prefix = Glib::ustring());
170+
171+
/** Add a child element to this node after the specified existing child node.
172+
*
173+
* @newin{3,0} Replaces Node::add_child_with_new_ns()
174+
*
175+
* @param previous_sibling An existing child node.
176+
* @param name The new node name.
177+
* @param ns_uri The namespace to associate with the prefix,
178+
* or to use as the default namespace if no prefix is specified.
179+
* @param ns_prefix The prefix of the node's namespace. If no prefix is specified
180+
* then the namespace URI will be the default namespace.
181+
* @returns The newly-created element.
182+
* @throws xmlpp::internal_error If this node is not an element node,
183+
* or the child node or the namespace node cannot be created.
184+
*/
185+
Element* add_child_element_with_new_ns(xmlpp::Node* previous_sibling, const Glib::ustring& name,
186+
const Glib::ustring& ns_uri, const Glib::ustring& ns_prefix = Glib::ustring());
187+
188+
/** Add a child element to this node before the specified existing child node.
189+
*
190+
* @newin{3,0} Replaces Node::add_child_before_with_new_ns()
191+
*
192+
* @param next_sibling An existing child node.
193+
* @param name The new node name.
194+
* @param ns_uri The namespace to associate with the prefix,
195+
* or to use as the default namespace if no prefix is specified.
196+
* @param ns_prefix The prefix of the node's namespace. If no prefix is specified
197+
* then the namespace URI will be the default namespace.
198+
* @returns The newly-created element.
199+
* @throws xmlpp::internal_error If this node is not an element node,
200+
* or the child node or the namespace node cannot be created.
201+
*/
202+
Element* add_child_element_before_with_new_ns(xmlpp::Node* next_sibling, const Glib::ustring& name,
203+
const Glib::ustring& ns_uri, const Glib::ustring& ns_prefix = Glib::ustring());
111204

112205
/** Get the first child text content node.
113-
* This is a convenience method, meant as an alternative to iterating over all the child nodes to find the first suitable node then and getting the text directly.
206+
* This is a convenience method, meant as an alternative to iterating over all the
207+
* child nodes to find the first suitable node then and getting the text directly.
114208
* @returns The first text node, if any.
115209
*/
116210
TextNode* get_child_text();
117211

118212
/** Get the first child text content node.
119-
* This is a convenience method, meant as an alternative to iterating over all the child nodes to find the first suitable node then and getting the text directly.
213+
* This is a convenience method, meant as an alternative to iterating over all the
214+
* child nodes to find the first suitable node then and getting the text directly.
120215
* @returns The first text node, if any.
121216
*/
122217
const TextNode* get_child_text() const;
@@ -205,8 +300,16 @@ class Element : public Node
205300
ProcessingInstructionNode* add_child_processing_instruction(
206301
const Glib::ustring& name, const Glib::ustring& content);
207302

208-
protected:
303+
private:
209304
Glib::ustring get_namespace_uri_for_prefix(const Glib::ustring& ns_prefix) const;
305+
306+
///Create the C instance ready to be added to the parent node.
307+
_xmlNode* create_new_child_element_node(const Glib::ustring& name,
308+
const Glib::ustring& ns_prefix);
309+
310+
///Create the C instance ready to be added to the parent node.
311+
_xmlNode* create_new_child_element_node_with_new_ns(const Glib::ustring& name,
312+
const Glib::ustring& ns_uri, const Glib::ustring& ns_prefix);
210313
};
211314

212315
} // namespace xmlpp

0 commit comments

Comments
 (0)