From a562014cc24ff060266de8c3cc951263e4efa750 Mon Sep 17 00:00:00 2001 From: "arseny.kapoulkine" Date: Sat, 12 Jun 2010 09:04:52 +0000 Subject: Declaration nodes improvements (they now automatically get name "xml", they can't be inserted as a non-document child, document saving prints declaration only if there is none present in the document) git-svn-id: http://pugixml.googlecode.com/svn/trunk@517 99668b35-9821-0410-8761-19e4c4f06640 --- src/pugixml.cpp | 54 +++++++++++++++++++++++++++++++++++++---------- tests/test_document.cpp | 35 ++++++++++++++++++++++++++++++ tests/test_dom_modify.cpp | 48 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 11 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 64b1e34..6184f92 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -2902,6 +2902,28 @@ namespace } } + inline bool has_declaration(const xml_node& node) + { + for (xml_node child = node.first_child(); child; child = child.next_sibling()) + { + xml_node_type type = child.type(); + + if (type == node_declaration) return true; + if (type == node_element) return false; + } + + return false; + } + + inline bool allow_insert_child(xml_node_type parent, xml_node_type child) + { + if (parent != node_document && parent != node_element) return false; + if (child == node_document || child == node_null) return false; + if (parent != node_document && child == node_declaration) return false; + + return true; + } + void recursive_copy_skip(xml_node& dest, const xml_node& source, const xml_node& skip) { assert(dest.type() == source.type()); @@ -3491,9 +3513,11 @@ namespace pugi xml_node xml_node::root() const { - xml_node r = *this; - while (r && r.parent()) r = r.parent(); - return r; + xml_node_struct* r = _root; + + while (r && r->parent) r = r->parent; + + return xml_node(r); } const char_t* xml_node::child_value() const @@ -3673,15 +3697,19 @@ namespace pugi xml_node xml_node::append_child(xml_node_type type) { - if ((this->type() != node_element && this->type() != node_document) || type == node_document || type == node_null) return xml_node(); + if (!allow_insert_child(this->type(), type)) return xml_node(); - return xml_node(append_node(_root, get_allocator(_root), type)); + xml_node n(append_node(_root, get_allocator(_root), type)); + + if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + + return n; } xml_node xml_node::insert_child_before(xml_node_type type, const xml_node& node) { - if ((this->type() != node_element && this->type() != node_document) || type == node_document || type == node_null) return xml_node(); - if (node.parent() != *this) return xml_node(); + if (!allow_insert_child(this->type(), type)) return xml_node(); + if (!node._root || node._root->parent != _root) return xml_node(); xml_node n(allocate_node(get_allocator(_root), type)); n._root->parent = _root; @@ -3695,13 +3723,15 @@ namespace pugi n._root->next_sibling = node._root; node._root->prev_sibling_c = n._root; + if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + return n; } xml_node xml_node::insert_child_after(xml_node_type type, const xml_node& node) { - if ((this->type() != node_element && this->type() != node_document) || type == node_document || type == node_null) return xml_node(); - if (node.parent() != *this) return xml_node(); + if (!allow_insert_child(this->type(), type)) return xml_node(); + if (!node._root || node._root->parent != _root) return xml_node(); xml_node n(allocate_node(get_allocator(_root), type)); n._root->parent = _root; @@ -3715,6 +3745,8 @@ namespace pugi n._root->prev_sibling_c = node._root; node._root->next_sibling = n._root; + if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + return n; } @@ -3777,7 +3809,7 @@ namespace pugi void xml_node::remove_child(const xml_node& n) { - if (!_root || n.parent() != *this) return; + if (!_root || !n._root || n._root->parent != _root) return; if (n._root->next_sibling) n._root->next_sibling->prev_sibling_c = n._root->prev_sibling_c; else if (_root->first_child) _root->first_child->prev_sibling_c = n._root->prev_sibling_c; @@ -4385,7 +4417,7 @@ namespace pugi xml_buffered_writer buffered_writer(writer, encoding); - if (!(flags & format_no_declaration)) + if (!(flags & format_no_declaration) && !has_declaration(*this)) { buffered_writer.write(PUGIXML_TEXT("")); if (!(flags & format_raw)) buffered_writer.write('\n'); diff --git a/tests/test_document.cpp b/tests/test_document.cpp index bed9498..11be6da 100644 --- a/tests/test_document.cpp +++ b/tests/test_document.cpp @@ -211,6 +211,41 @@ TEST_XML(document_save_declaration, "") CHECK(writer.as_string() == STR("\n\n")); } +TEST_XML(document_save_declaration_present_first, "") +{ + doc.insert_child_before(node_declaration, doc.first_child()).append_attribute(STR("encoding")) = STR("utf8"); + + xml_writer_string writer; + + doc.save(writer, STR(""), pugi::format_default, get_native_encoding()); + + CHECK(writer.as_string() == STR("\n\n")); +} + +TEST_XML(document_save_declaration_present_second, "") +{ + doc.insert_child_before(node_declaration, doc.first_child()).append_attribute(STR("encoding")) = STR("utf8"); + doc.insert_child_before(node_comment, doc.first_child()).set_value(STR("text")); + + xml_writer_string writer; + + doc.save(writer, STR(""), pugi::format_default, get_native_encoding()); + + CHECK(writer.as_string() == STR("\n\n\n")); +} + +TEST_XML(document_save_declaration_present_last, "") +{ + doc.append_child(node_declaration).append_attribute(STR("encoding")) = STR("utf8"); + + xml_writer_string writer; + + doc.save(writer, STR(""), pugi::format_default, get_native_encoding()); + + // node writer only looks for declaration before the first element child + CHECK(writer.as_string() == STR("\n\n\n")); +} + TEST_XML(document_save_file, "") { #ifdef __unix diff --git a/tests/test_dom_modify.cpp b/tests/test_dom_modify.cpp index 31647d4..e1e47f7 100644 --- a/tests/test_dom_modify.cpp +++ b/tests/test_dom_modify.cpp @@ -532,3 +532,51 @@ TEST_XML(dom_attr_assign_large_number, "") CHECK(test_node(node, STR(""), STR(""), pugi::format_raw) || test_node(node, STR(""), STR(""), pugi::format_raw)); } + +TEST(dom_node_declaration_name) +{ + xml_document doc; + doc.append_child(node_declaration); + + // name 'xml' is auto-assigned + CHECK(doc.first_child().type() == node_declaration); + CHECK_STRING(doc.first_child().name(), STR("xml")); + + doc.insert_child_after(node_declaration, doc.first_child()); + doc.insert_child_before(node_declaration, doc.first_child()); + + CHECK_NODE(doc, STR("")); +} + +TEST(dom_node_declaration_top_level) +{ + xml_document doc; + doc.append_child().set_name(STR("node")); + + xml_node node = doc.first_child(); + node.append_child(node_pcdata).set_value(STR("text")); + + CHECK(node.insert_child_before(node_declaration, node.first_child()) == xml_node()); + CHECK(node.insert_child_after(node_declaration, node.first_child()) == xml_node()); + CHECK(node.append_child(node_declaration) == xml_node()); + + CHECK_NODE(doc, STR("text")); + + CHECK(doc.insert_child_before(node_declaration, node)); + CHECK(doc.insert_child_after(node_declaration, node)); + CHECK(doc.append_child(node_declaration)); + + CHECK_NODE(doc, STR("text")); +} + +TEST(dom_node_declaration_copy) +{ + xml_document doc; + doc.append_child(node_declaration); + + doc.append_child().set_name(STR("node")); + + doc.last_child().append_copy(doc.first_child()); + + CHECK_NODE(doc, STR("")); +} -- cgit v1.2.3