0
0
mirror of https://github.com/zeux/pugixml.git synced 2025-01-13 17:37:58 +08:00

feat: add remove_attributes() and remove_children() (#296)

These functions remove all attributes / child nodes in bulk which is faster than removing them one at a time.
This commit is contained in:
Tuan Anh Tran 2019-09-18 10:18:41 +07:00 committed by Arseny Kapoulkine
parent ccb63a9186
commit fd7326fb91
4 changed files with 80 additions and 2 deletions

View File

@ -1378,16 +1378,18 @@ include::samples/modify_add.cpp[tags=code]
[[modify.remove]] [[modify.remove]]
=== Removing nodes/attributes === Removing nodes/attributes
[[xml_node::remove_attribute]][[xml_node::remove_child]] [[xml_node::remove_attribute]][[xml_node::remove_attributes]][[xml_node::remove_child]][[xml_node::remove_children]]
If you do not want your document to contain some node or attribute, you can remove it with one of the following functions: If you do not want your document to contain some node or attribute, you can remove it with one of the following functions:
[source] [source]
---- ----
bool xml_node::remove_attribute(const xml_attribute& a); bool xml_node::remove_attribute(const xml_attribute& a);
bool xml_node::remove_attributes();
bool xml_node::remove_child(const xml_node& n); bool xml_node::remove_child(const xml_node& n);
bool xml_node::remove_children();
---- ----
`remove_attribute` removes the attribute from the attribute list of the node, and returns the operation result. `remove_child` removes the child node with the entire subtree (including all descendant nodes and attributes) from the document, and returns the operation result. Removing fails if one of the following is true: `remove_attribute` removes the attribute from the attribute list of the node, and returns the operation result. `remove_child` removes the child node with the entire subtree (including all descendant nodes and attributes) from the document, and returns the operation result. `remove_attributes` removes all the attributes of the node, and returns the operation result. `remove_children` removes all the child nodes of the node, and returns the operation result. Removing fails if one of the following is true:
* The node the function is called on is null; * The node the function is called on is null;
* The attribute/node to be removed is null; * The attribute/node to be removed is null;
@ -2868,8 +2870,10 @@ const unsigned int +++<a href="#parse_wnorm_attribute">parse_wnorm_attribute</a>
bool +++<a href="#xml_node::remove_attribute">remove_attribute</a>+++(const xml_attribute& a); bool +++<a href="#xml_node::remove_attribute">remove_attribute</a>+++(const xml_attribute& a);
bool +++<a href="#xml_node::remove_attribute">remove_attribute</a>+++(const char_t* name); bool +++<a href="#xml_node::remove_attribute">remove_attribute</a>+++(const char_t* name);
bool +++<a href="#xml_node::remove_attributes">remove_attributes</a>+++();
bool +++<a href="#xml_node::remove_child">remove_child</a>+++(const xml_node& n); bool +++<a href="#xml_node::remove_child">remove_child</a>+++(const xml_node& n);
bool +++<a href="#xml_node::remove_child">remove_child</a>+++(const char_t* name); bool +++<a href="#xml_node::remove_child">remove_child</a>+++(const char_t* name);
bool +++<a href="#xml_node::remove_children">remove_children</a>+++();
xml_parse_result +++<a href="#xml_node::append_buffer">append_buffer</a>+++(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); xml_parse_result +++<a href="#xml_node::append_buffer">append_buffer</a>+++(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);

View File

@ -6059,6 +6059,27 @@ namespace pugi
return true; return true;
} }
PUGI__FN bool xml_node::remove_attributes()
{
if (!_root) return false;
impl::xml_allocator& alloc = impl::get_allocator(_root);
if (!alloc.reserve()) return false;
for (xml_attribute_struct* attr = _root->first_attribute; attr;)
{
xml_attribute_struct* next = attr->next_attribute;
impl::destroy_attribute(attr, alloc);
attr = next;
}
_root->first_attribute = 0;
return true;
}
PUGI__FN bool xml_node::remove_child(const char_t* name_) PUGI__FN bool xml_node::remove_child(const char_t* name_)
{ {
return remove_child(child(name_)); return remove_child(child(name_));
@ -6077,6 +6098,27 @@ namespace pugi
return true; return true;
} }
PUGI__FN bool xml_node::remove_children()
{
if (!_root) return false;
impl::xml_allocator& alloc = impl::get_allocator(_root);
if (!alloc.reserve()) return false;
for (xml_node_struct* child = _root->first_child; child; )
{
xml_node_struct* next = child->next_sibling;
destroy_node(child, alloc);
child = next;
}
_root->first_child = 0;
return true;
}
PUGI__FN xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) PUGI__FN xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)
{ {
// append_buffer is only valid for elements/documents // append_buffer is only valid for elements/documents

View File

@ -576,10 +576,16 @@ namespace pugi
bool remove_attribute(const xml_attribute& a); bool remove_attribute(const xml_attribute& a);
bool remove_attribute(const char_t* name); bool remove_attribute(const char_t* name);
// Remove all attributes
bool remove_attributes();
// Remove specified child // Remove specified child
bool remove_child(const xml_node& n); bool remove_child(const xml_node& n);
bool remove_child(const char_t* name); bool remove_child(const char_t* name);
// Remove all children
bool remove_children();
// Parses buffer as an XML document fragment and appends all nodes as children of the current node. // Parses buffer as an XML document fragment and appends all nodes as children of the current node.
// Copies/converts the buffer, so it may be deleted or changed after the function returns. // Copies/converts the buffer, so it may be deleted or changed after the function returns.
// Note: append_buffer allocates memory that has the lifetime of the owning document; removing the appended nodes does not immediately reclaim that memory. // Note: append_buffer allocates memory that has the lifetime of the owning document; removing the appended nodes does not immediately reclaim that memory.

View File

@ -492,6 +492,19 @@ TEST_XML(dom_node_remove_attribute, "<node a1='v1' a2='v2' a3='v3'><child a4='v4
CHECK_NODE(doc, STR("<node a2=\"v2\"><child/></node>")); CHECK_NODE(doc, STR("<node a2=\"v2\"><child/></node>"));
} }
TEST_XML(dom_node_remove_attributes, "<node a1='v1' a2='v2' a3='v3'><child a4='v4'/></node>")
{
CHECK(!xml_node().remove_attributes());
xml_node node = doc.child(STR("node"));
xml_node child = node.child(STR("child"));
CHECK(child.remove_attributes());
CHECK_NODE(child, STR("<child/>"));
CHECK(node.remove_attributes());
CHECK_NODE(node, STR("<node><child/></node>"));
}
TEST_XML(dom_node_prepend_child, "<node>foo<child/></node>") TEST_XML(dom_node_prepend_child, "<node>foo<child/></node>")
{ {
CHECK(xml_node().prepend_child() == xml_node()); CHECK(xml_node().prepend_child() == xml_node());
@ -707,6 +720,19 @@ TEST_XML(dom_node_remove_child, "<node><n1/><n2/><n3/><child><n4/></child></node
CHECK_NODE(doc, STR("<node><n2/><child/></node>")); CHECK_NODE(doc, STR("<node><n2/><child/></node>"));
} }
TEST_XML(dom_node_remove_children, "<node><n1/><n2/><n3/><child><n4/></child></node>")
{
CHECK(!xml_node().remove_children());
xml_node node = doc.child(STR("node"));
xml_node child = node.child(STR("child"));
CHECK(child.remove_children());
CHECK_NODE(child, STR("<child/>"));
CHECK(node.remove_children());
CHECK_NODE(node, STR("<node/>"));
}
TEST_XML(dom_node_remove_child_complex, "<node id='1'><n1 id1='1' id2='2'/><n2/><n3/><child><n4/></child></node>") TEST_XML(dom_node_remove_child_complex, "<node id='1'><n1 id1='1' id2='2'/><n2/><n3/><child><n4/></child></node>")
{ {
CHECK(doc.child(STR("node")).remove_child(STR("n1"))); CHECK(doc.child(STR("node")).remove_child(STR("n1")));