diff options
| -rw-r--r-- | src/pugixml.cpp | 54 | ||||
| -rw-r--r-- | tests/test_document.cpp | 35 | ||||
| -rw-r--r-- | 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("<?xml version=\"1.0\"?>"));
  			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, "<node/>")  	CHECK(writer.as_string() == STR("<?xml version=\"1.0\"?>\n<node />\n"));
  }
 +TEST_XML(document_save_declaration_present_first, "<node/>")
 +{
 +	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("<?xml encoding=\"utf8\"?>\n<node />\n"));
 +}
 +
 +TEST_XML(document_save_declaration_present_second, "<node/>")
 +{
 +	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("<!--text-->\n<?xml encoding=\"utf8\"?>\n<node />\n"));
 +}
 +
 +TEST_XML(document_save_declaration_present_last, "<node/>")
 +{
 +	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("<?xml version=\"1.0\"?>\n<node />\n<?xml encoding=\"utf8\"?>\n"));
 +}
 +
  TEST_XML(document_save_file, "<node/>")
  {
  #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, "<node attr1='' attr2='' />")  	CHECK(test_node(node, STR("<node attr1=\"3.40282e+038\" attr2=\"1.79769e+308\" />"), STR(""), pugi::format_raw) ||
  		  test_node(node, STR("<node attr1=\"3.40282e+38\" attr2=\"1.79769e+308\" />"), 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("<?xml?><?xml?><?xml?>"));
 +}
 +
 +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("<node>text</node>"));
 +
 +	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("<?xml?><node>text</node><?xml?><?xml?>"));
 +}
 +
 +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("<?xml?><node />"));
 +}
 | 
