diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 1abd80c..b84658d 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -252,6 +252,24 @@ PUGI_IMPL_NS_BEGIN
#endif
}
+#ifdef PUGIXML_HAS_STRING_VIEW
+ // Check if the null-terminated dst string is equal to the entire contents of srcview
+ PUGI_IMPL_FN bool stringview_equal(string_view_t srcview, const char_t* dst)
+ {
+ // std::basic_string_view::compare(const char*) has the right behavior, but it performs an
+ // extra traversal of dst to compute its length.
+ assert(dst);
+ const char_t* src = srcview.data();
+ size_t srclen = srcview.size();
+
+ while (srclen && *dst && *src == *dst)
+ {
+ --srclen; ++dst; ++src;
+ }
+ return srclen == 0 && *dst == 0;
+ }
+#endif
+
// Compare lhs with [rhs_begin, rhs_end)
PUGI_IMPL_FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count)
{
@@ -5413,6 +5431,14 @@ namespace pugi
return *this;
}
+#ifdef PUGIXML_HAS_STRING_VIEW
+ PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(string_view_t rhs)
+ {
+ set_value(rhs);
+ return *this;
+ }
+#endif
+
#ifdef PUGIXML_HAS_LONG_LONG
PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(long long rhs)
{
@@ -5736,6 +5762,64 @@ namespace pugi
return xml_node();
}
+#ifdef PUGIXML_HAS_STRING_VIEW
+ PUGI_IMPL_FN xml_node xml_node::child(string_view_t name_) const
+ {
+ if (!_root) return xml_node();
+
+ for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
+ {
+ const char_t* iname = i->name;
+ if (iname && impl::stringview_equal(name_, iname))
+ return xml_node(i);
+ }
+
+ return xml_node();
+ }
+
+ PUGI_IMPL_FN xml_attribute xml_node::attribute(string_view_t name_) const
+ {
+ if (!_root) return xml_attribute();
+
+ for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute)
+ {
+ const char_t* iname = i->name;
+ if (iname && impl::stringview_equal(name_, iname))
+ return xml_attribute(i);
+ }
+
+ return xml_attribute();
+ }
+
+ PUGI_IMPL_FN xml_node xml_node::next_sibling(string_view_t name_) const
+ {
+ if (!_root) return xml_node();
+
+ for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling)
+ {
+ const char_t* iname = i->name;
+ if (iname && impl::stringview_equal(name_, iname))
+ return xml_node(i);
+ }
+
+ return xml_node();
+ }
+
+ PUGI_IMPL_FN xml_node xml_node::previous_sibling(string_view_t name_) const
+ {
+ if (!_root) return xml_node();
+
+ for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c)
+ {
+ const char_t* iname = i->name;
+ if (iname && impl::stringview_equal(name_, iname))
+ return xml_node(i);
+ }
+
+ return xml_node();
+ }
+#endif
+
PUGI_IMPL_FN xml_attribute xml_node::attribute(const char_t* name_, xml_attribute& hint_) const
{
xml_attribute_struct* hint = hint_._attr;
@@ -5775,6 +5859,47 @@ namespace pugi
return xml_attribute();
}
+#ifdef PUGIXML_HAS_STRING_VIEW
+ PUGI_IMPL_FN xml_attribute xml_node::attribute(string_view_t name_, xml_attribute& hint_) const
+ {
+ xml_attribute_struct* hint = hint_._attr;
+
+ // if hint is not an attribute of node, behavior is not defined
+ assert(!hint || (_root && impl::is_attribute_of(hint, _root)));
+
+ if (!_root) return xml_attribute();
+
+ // optimistically search from hint up until the end
+ for (xml_attribute_struct* i = hint; i; i = i->next_attribute)
+ {
+ const char_t* iname = i->name;
+ if (iname && impl::stringview_equal(name_, iname))
+ {
+ // update hint to maximize efficiency of searching for consecutive attributes
+ hint_._attr = i->next_attribute;
+
+ return xml_attribute(i);
+ }
+ }
+
+ // wrap around and search from the first attribute until the hint
+ // 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails
+ for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute)
+ {
+ const char_t* jname = j->name;
+ if (jname && impl::stringview_equal(name_, jname))
+ {
+ // update hint to maximize efficiency of searching for consecutive attributes
+ hint_._attr = j->next_attribute;
+
+ return xml_attribute(j);
+ }
+ }
+
+ return xml_attribute();
+ }
+#endif
+
PUGI_IMPL_FN xml_node xml_node::previous_sibling() const
{
if (!_root) return xml_node();
@@ -5980,6 +6105,78 @@ namespace pugi
return a;
}
+#ifdef PUGIXML_HAS_STRING_VIEW
+ PUGI_IMPL_FN xml_attribute xml_node::append_attribute(string_view_t name_)
+ {
+ if (!impl::allow_insert_attribute(type())) return xml_attribute();
+
+ impl::xml_allocator& alloc = impl::get_allocator(_root);
+ if (!alloc.reserve()) return xml_attribute();
+
+ xml_attribute a(impl::allocate_attribute(alloc));
+ if (!a) return xml_attribute();
+
+ impl::append_attribute(a._attr, _root);
+
+ a.set_name(name_);
+
+ return a;
+ }
+
+ PUGI_IMPL_FN xml_attribute xml_node::prepend_attribute(string_view_t name_)
+ {
+ if (!impl::allow_insert_attribute(type())) return xml_attribute();
+
+ impl::xml_allocator& alloc = impl::get_allocator(_root);
+ if (!alloc.reserve()) return xml_attribute();
+
+ xml_attribute a(impl::allocate_attribute(alloc));
+ if (!a) return xml_attribute();
+
+ impl::prepend_attribute(a._attr, _root);
+
+ a.set_name(name_);
+
+ return a;
+ }
+
+ PUGI_IMPL_FN xml_attribute xml_node::insert_attribute_after(string_view_t name_, const xml_attribute& attr)
+ {
+ if (!impl::allow_insert_attribute(type())) return xml_attribute();
+ if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
+
+ impl::xml_allocator& alloc = impl::get_allocator(_root);
+ if (!alloc.reserve()) return xml_attribute();
+
+ xml_attribute a(impl::allocate_attribute(alloc));
+ if (!a) return xml_attribute();
+
+ impl::insert_attribute_after(a._attr, attr._attr, _root);
+
+ a.set_name(name_);
+
+ return a;
+ }
+
+ PUGI_IMPL_FN xml_attribute xml_node::insert_attribute_before(string_view_t name_, const xml_attribute& attr)
+ {
+ if (!impl::allow_insert_attribute(type())) return xml_attribute();
+ if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
+
+ impl::xml_allocator& alloc = impl::get_allocator(_root);
+ if (!alloc.reserve()) return xml_attribute();
+
+ xml_attribute a(impl::allocate_attribute(alloc));
+ if (!a) return xml_attribute();
+
+ impl::insert_attribute_before(a._attr, attr._attr, _root);
+
+ a.set_name(name_);
+
+ return a;
+ }
+#endif
+
PUGI_IMPL_FN xml_attribute xml_node::append_copy(const xml_attribute& proto)
{
if (!proto) return xml_attribute();
@@ -6156,6 +6353,44 @@ namespace pugi
return result;
}
+#ifdef PUGIXML_HAS_STRING_VIEW
+ PUGI_IMPL_FN xml_node xml_node::append_child(string_view_t name_)
+ {
+ xml_node result = append_child(node_element);
+
+ result.set_name(name_);
+
+ return result;
+ }
+
+ PUGI_IMPL_FN xml_node xml_node::prepend_child(string_view_t name_)
+ {
+ xml_node result = prepend_child(node_element);
+
+ result.set_name(name_);
+
+ return result;
+ }
+
+ PUGI_IMPL_FN xml_node xml_node::insert_child_after(string_view_t name_, const xml_node& node)
+ {
+ xml_node result = insert_child_after(node_element, node);
+
+ result.set_name(name_);
+
+ return result;
+ }
+
+ PUGI_IMPL_FN xml_node xml_node::insert_child_before(string_view_t name_, const xml_node& node)
+ {
+ xml_node result = insert_child_before(node_element, node);
+
+ result.set_name(name_);
+
+ return result;
+ }
+#endif
+
PUGI_IMPL_FN xml_node xml_node::append_copy(const xml_node& proto)
{
xml_node_type type_ = proto.type();
@@ -6299,6 +6534,13 @@ namespace pugi
return remove_attribute(attribute(name_));
}
+#ifdef PUGIXML_HAS_STRING_VIEW
+ PUGI_IMPL_FN bool xml_node::remove_attribute(string_view_t name_)
+ {
+ return remove_attribute(attribute(name_));
+ }
+#endif
+
PUGI_IMPL_FN bool xml_node::remove_attribute(const xml_attribute& a)
{
if (!_root || !a._attr) return false;
@@ -6339,6 +6581,13 @@ namespace pugi
return remove_child(child(name_));
}
+#ifdef PUGIXML_HAS_STRING_VIEW
+ PUGI_IMPL_FN bool xml_node::remove_child(string_view_t name_)
+ {
+ return remove_child(child(name_));
+ }
+#endif
+
PUGI_IMPL_FN bool xml_node::remove_child(const xml_node& n)
{
if (!_root || !n._root || n._root->parent != _root) return false;
@@ -6935,6 +7184,14 @@ namespace pugi
return *this;
}
+#ifdef PUGIXML_HAS_STRING_VIEW
+ PUGI_IMPL_FN xml_text& xml_text::operator=(string_view_t rhs)
+ {
+ set(rhs);
+ return *this;
+ }
+#endif
+
#ifdef PUGIXML_HAS_LONG_LONG
PUGI_IMPL_FN xml_text& xml_text::operator=(long long rhs)
{
diff --git a/src/pugixml.hpp b/src/pugixml.hpp
index 4bad982..f2d985e 100644
--- a/src/pugixml.hpp
+++ b/src/pugixml.hpp
@@ -477,6 +477,10 @@ namespace pugi
xml_attribute& operator=(float rhs);
xml_attribute& operator=(bool rhs);
+ #ifdef PUGIXML_HAS_STRING_VIEW
+ xml_attribute& operator=(string_view_t rhs);
+ #endif
+
#ifdef PUGIXML_HAS_LONG_LONG
xml_attribute& operator=(long long rhs);
xml_attribute& operator=(unsigned long long rhs);
@@ -571,9 +575,18 @@ namespace pugi
xml_attribute attribute(const char_t* name) const;
xml_node next_sibling(const char_t* name) const;
xml_node previous_sibling(const char_t* name) const;
+ #ifdef PUGIXML_HAS_STRING_VIEW
+ xml_node child(string_view_t name) const;
+ xml_attribute attribute(string_view_t name) const;
+ xml_node next_sibling(string_view_t name) const;
+ xml_node previous_sibling(string_view_t name) const;
+ #endif
// Get attribute, starting the search from a hint (and updating hint so that searching for a sequence of attributes is fast)
xml_attribute attribute(const char_t* name, xml_attribute& hint) const;
+ #ifdef PUGIXML_HAS_STRING_VIEW
+ xml_attribute attribute(string_view_t name, xml_attribute& hint) const;
+ #endif
// Get child value of current node; that is, value of the first child node of type PCDATA/CDATA
const char_t* child_value() const;
@@ -598,6 +611,12 @@ namespace pugi
xml_attribute prepend_attribute(const char_t* name);
xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr);
xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr);
+ #ifdef PUGIXML_HAS_STRING_VIEW
+ xml_attribute append_attribute(string_view_t name);
+ xml_attribute prepend_attribute(string_view_t name);
+ xml_attribute insert_attribute_after(string_view_t name, const xml_attribute& attr);
+ xml_attribute insert_attribute_before(string_view_t name, const xml_attribute& attr);
+ #endif
// Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors.
xml_attribute append_copy(const xml_attribute& proto);
@@ -616,6 +635,12 @@ namespace pugi
xml_node prepend_child(const char_t* name);
xml_node insert_child_after(const char_t* name, const xml_node& node);
xml_node insert_child_before(const char_t* name, const xml_node& node);
+ #ifdef PUGIXML_HAS_STRING_VIEW
+ xml_node append_child(string_view_t name);
+ xml_node prepend_child(string_view_t name);
+ xml_node insert_child_after(string_view_t, const xml_node& node);
+ xml_node insert_child_before(string_view_t name, const xml_node& node);
+ #endif
// Add a copy of the specified node as a child. Returns added node, or empty node on errors.
xml_node append_copy(const xml_node& proto);
@@ -632,6 +657,9 @@ namespace pugi
// Remove specified attribute
bool remove_attribute(const xml_attribute& a);
bool remove_attribute(const char_t* name);
+ #ifdef PUGIXML_HAS_STRING_VIEW
+ bool remove_attribute(string_view_t name);
+ #endif
// Remove all attributes
bool remove_attributes();
@@ -639,6 +667,9 @@ namespace pugi
// Remove specified child
bool remove_child(const xml_node& n);
bool remove_child(const char_t* name);
+ #ifdef PUGIXML_HAS_STRING_VIEW
+ bool remove_child(string_view_t name);
+ #endif
// Remove all children
bool remove_children();
@@ -851,6 +882,10 @@ namespace pugi
xml_text& operator=(float rhs);
xml_text& operator=(bool rhs);
+ #ifdef PUGIXML_HAS_STRING_VIEW
+ xml_text& operator=(string_view_t rhs);
+ #endif
+
#ifdef PUGIXML_HAS_LONG_LONG
xml_text& operator=(long long rhs);
xml_text& operator=(unsigned long long rhs);
diff --git a/tests/test_dom_modify.cpp b/tests/test_dom_modify.cpp
index 71dc554..6188531 100644
--- a/tests/test_dom_modify.cpp
+++ b/tests/test_dom_modify.cpp
@@ -33,7 +33,13 @@ TEST_XML(dom_attr_assign, "")
node.append_attribute(STR("attr8")) = true;
xml_attribute() = true;
- CHECK_NODE(node, STR(""));
+#ifdef PUGIXML_HAS_STRING_VIEW
+ node.append_attribute(string_view_t(STR("attr9"))) = string_view_t(STR("v2"));
+#else
+ node.append_attribute(STR("attr9")) = STR("v2");
+#endif
+
+ CHECK_NODE(node, STR(""));
}
TEST_XML(dom_attr_set_name, "")
@@ -103,7 +109,14 @@ TEST_XML(dom_attr_set_value, "")
CHECK(node.append_attribute(STR("attr10")).set_value(STR("v3foobar"), 2));
CHECK(!xml_attribute().set_value(STR("v3")));
- CHECK_NODE(node, STR(""));
+#ifdef PUGIXML_HAS_STRING_VIEW
+ CHECK(node.append_attribute(string_view_t(STR("attr11"))).set_value(string_view_t(STR("v4"))));
+ CHECK(!xml_attribute().set_value(string_view_t(STR("v4"))));
+#else
+ CHECK(node.append_attribute(STR("attr11")).set_value(STR("v4")));
+#endif
+
+ CHECK_NODE(node, STR(""));
}
#if LONG_MAX > 2147483647
@@ -335,7 +348,15 @@ TEST_XML(dom_node_prepend_attribute, "")
CHECK(a3 && a1 != a3 && a2 != a3);
a3 = STR("v3");
- CHECK_NODE(doc, STR(""));
+#ifdef PUGIXML_HAS_STRING_VIEW
+ xml_attribute a4 = doc.child(STR("node")).child(STR("child")).prepend_attribute(string_view_t(STR("a4")));
+#else
+ xml_attribute a4 = doc.child(STR("node")).child(STR("child")).prepend_attribute(STR("a4"));
+#endif
+ CHECK(a4 && a1 != a4 && a2 != a4 && a3 != a4);
+ a4 = STR("v4");
+
+ CHECK_NODE(doc, STR(""));
}
TEST_XML(dom_node_append_attribute, "")
@@ -385,7 +406,17 @@ TEST_XML(dom_node_insert_attribute_after, "
CHECK(child.insert_attribute_after(STR("a"), a4) == xml_attribute());
- CHECK_NODE(doc, STR(""));
+#ifdef PUGIXML_HAS_STRING_VIEW
+ xml_attribute a6 = node.insert_attribute_after(string_view_t(STR("a6")), a5);
+ CHECK(child.insert_attribute_after(string_view_t(STR("a")), a5) == xml_attribute());
+#else
+ xml_attribute a6 = node.insert_attribute_after(STR("a6"), a5);
+ CHECK(child.insert_attribute_after(STR("a"), a5) == xml_attribute());
+#endif
+ CHECK(a6 && a6 != a5 && a6 != a4 && a6 != a3 && a6 != a2 && a6 != a1);
+ a6 = STR("v6");
+
+ CHECK_NODE(doc, STR(""));
}
TEST_XML(dom_node_insert_attribute_before, "")
@@ -415,7 +446,17 @@ TEST_XML(dom_node_insert_attribute_before, ""));
+#ifdef PUGIXML_HAS_STRING_VIEW
+ xml_attribute a6 = node.insert_attribute_before(string_view_t(STR("a6")), a1);
+ CHECK(child.insert_attribute_before(string_view_t(STR("a")), a4) == xml_attribute());
+#else
+ xml_attribute a6 = node.insert_attribute_before(STR("a6"), a1);
+ CHECK(child.insert_attribute_before(STR("a"), a4) == xml_attribute());
+#endif
+ CHECK(a6 && a6 != a5 && a6 != a4 && a6 != a3 && a6 != a2 && a6 != a1);
+ a6 = STR("v6");
+
+ CHECK_NODE(doc, STR(""));
}
TEST_XML(dom_node_prepend_copy_attribute, "")
@@ -589,6 +630,14 @@ TEST_XML(dom_node_remove_attribute, "")
@@ -747,6 +796,10 @@ TEST_XML(dom_node_prepend_child_name, "foo")
{
CHECK(xml_node().prepend_child(STR("")) == xml_node());
CHECK(doc.child(STR("node")).first_child().prepend_child(STR("")) == xml_node());
+#ifdef PUGIXML_HAS_STRING_VIEW
+ CHECK(xml_node().prepend_child(string_view_t()) == xml_node());
+ CHECK(doc.child(STR("node")).first_child().prepend_child(string_view_t()) == xml_node());
+#endif
xml_node n1 = doc.child(STR("node")).prepend_child(STR("n1"));
CHECK(n1);
@@ -754,7 +807,14 @@ TEST_XML(dom_node_prepend_child_name, "foo")
xml_node n2 = doc.child(STR("node")).prepend_child(STR("n2"));
CHECK(n2 && n1 != n2);
- CHECK_NODE(doc, STR("foo"));
+#ifdef PUGIXML_HAS_STRING_VIEW
+ xml_node n3 = doc.prepend_child(string_view_t(STR("n3")));
+#else
+ xml_node n3 = doc.prepend_child(STR("n3"));
+#endif
+ CHECK(n3 && n1 != n3 && n2 != n3);
+
+ CHECK_NODE(doc, STR("foo"));
}
TEST_XML(dom_node_append_child_name, "foo")
@@ -768,7 +828,14 @@ TEST_XML(dom_node_append_child_name, "foo")
xml_node n2 = doc.child(STR("node")).append_child(STR("n2"));
CHECK(n2 && n1 != n2);
- CHECK_NODE(doc, STR("foo"));
+#ifdef PUGIXML_HAS_STRING_VIEW
+ xml_node n3 = doc.append_child(string_view_t(STR("n3")));
+#else
+ xml_node n3 = doc.append_child(STR("n3"));
+#endif
+ CHECK(n3 && n3 != n2 && n3 != n1);
+
+ CHECK_NODE(doc, STR("foo"));
}
TEST_XML(dom_node_insert_child_after_name, "foo")
@@ -790,7 +857,14 @@ TEST_XML(dom_node_insert_child_after_name, "foo")
CHECK(child.insert_child_after(STR(""), n2) == xml_node());
- CHECK_NODE(doc, STR("foo"));
+#ifdef PUGIXML_HAS_STRING_VIEW
+ xml_node n3 = node.insert_child_after(string_view_t(STR("n3")), n1);
+#else
+ xml_node n3 = node.insert_child_after(STR("n3"), n1);
+#endif
+ CHECK(n3 && n3 != node && n3 != child && n3 != n2 && n3 != n1);
+
+ CHECK_NODE(doc, STR("foo"));
}
TEST_XML(dom_node_insert_child_before_name, "foo")
@@ -812,7 +886,14 @@ TEST_XML(dom_node_insert_child_before_name, "foo")
CHECK(child.insert_child_before(STR(""), n2) == xml_node());
- CHECK_NODE(doc, STR("foo"));
+#ifdef PUGIXML_HAS_STRING_VIEW
+ xml_node n3 = node.insert_child_before(string_view_t(STR("n3")), child);
+#else
+ xml_node n3 = node.insert_child_before(STR("n3"), child);
+#endif
+ CHECK(n3 && n3 != node && n3 != child && n3 != n2 && n3 != n1);
+
+ CHECK_NODE(doc, STR("foo"));
}
TEST_XML(dom_node_remove_child, "")
@@ -834,6 +915,20 @@ TEST_XML(dom_node_remove_child, ""));
+
+#ifdef PUGIXML_HAS_STRING_VIEW
+ CHECK(!node.remove_child(string_view_t()));
+ CHECK(!node.remove_child(string_view_t(STR("child"), 3)));
+ CHECK(!node.remove_child(string_view_t(STR("n2"), 1)));
+
+ CHECK_NODE(doc, STR(""));
+
+ CHECK(node.remove_child(string_view_t(STR("child"))));
+ CHECK_NODE(doc, STR(""));
+
+ CHECK(node.remove_child(string_view_t(STR("n2_notinview"), 2)));
+ CHECK_NODE(doc, STR(""));
+#endif
}
TEST_XML(dom_node_remove_children, "")
diff --git a/tests/test_dom_text.cpp b/tests/test_dom_text.cpp
index d14284d..71edc70 100644
--- a/tests/test_dom_text.cpp
+++ b/tests/test_dom_text.cpp
@@ -388,7 +388,14 @@ TEST_XML(dom_text_assign, "")
node.append_child(STR("text8")).text() = true;
xml_text() = true;
- CHECK_NODE(node, STR("v1-2147483647-2147483648429496729542949672940.50.25true"));
+#ifdef PUGIXML_HAS_STRING_VIEW
+ node.append_child(string_view_t(STR("text9"))).text() = string_view_t(STR("v2"));
+ xml_text() = string_view_t(STR("text9"));
+#else
+ node.append_child(STR("text9")).text() = STR("v2");
+#endif
+
+ CHECK_NODE(node, STR("v1-2147483647-2147483648429496729542949672940.50.25truev2"));
}
TEST_XML(dom_text_set_value, "")
diff --git a/tests/test_dom_traverse.cpp b/tests/test_dom_traverse.cpp
index 0c1e3af..18b93ef 100644
--- a/tests/test_dom_traverse.cpp
+++ b/tests/test_dom_traverse.cpp
@@ -536,6 +536,42 @@ TEST_XML(dom_node_child, "")
CHECK(doc.child(STR("node")).child(STR("child2")) == doc.child(STR("node")).last_child());
}
+#ifdef PUGIXML_HAS_STRING_VIEW
+TEST_XML(dom_node_child_stringview, "")
+{
+ CHECK(xml_node().child(string_view_t(STR("n"))) == xml_node());
+ CHECK(doc.child(string_view_t()) == xml_node());
+ CHECK(doc.child(string_view_t(STR("n"))) == xml_node());
+
+ xml_node node = doc.child(string_view_t(STR("node")));
+ CHECK_NAME_VALUE(node, STR("node"), STR(""));
+ CHECK(node.child(string_view_t(STR("child2"))) == node.last_child());
+
+ // verify only the characters in the view of the string view are included in the comparison
+ CHECK_NAME_VALUE(doc.child(string_view_t(STR("node_andextratext"), 4)), STR("node"), STR(""));
+ CHECK(doc.child(string_view_t(STR("node"), 2)) == xml_node());
+}
+
+TEST_XML(dom_node_child_interior_null, "")
+{
+ const char_t name[] = STR("node\0extra");
+ size_t len = (sizeof(name) / sizeof(char_t)) - 1;
+ CHECK(len == 10);
+
+ xml_node node = doc.child(string_view_t(name, 4)); // "node" view excluding null
+ CHECK_NAME_VALUE(node, STR("node"), STR(""));
+ CHECK(doc.child(string_view_t(name, 5)) == xml_node()); // "node\0" view including null
+ CHECK(doc.child(string_view_t(name, len)) == xml_node()); // "node\0extra" view
+
+ node.set_name(string_view_t(name, len));
+ CHECK_NODE(doc, STR(""));
+ CHECK_NAME_VALUE(node, STR("node"), STR(""));
+ CHECK_NAME_VALUE(doc.child(string_view_t(name, 4)), STR("node"), STR("")); // "node" view excluding null
+ CHECK(doc.child(string_view_t(name, 5)) == xml_node()); // "node\0" view including null
+ CHECK(doc.child(string_view_t(name, len)) == xml_node()); // "node\0extra" view
+}
+#endif
+
TEST_XML(dom_node_attribute, "")
{
CHECK(xml_node().attribute(STR("a")) == xml_attribute());
@@ -547,6 +583,46 @@ TEST_XML(dom_node_attribute, "")
CHECK(node.attribute(STR("attr2")) == node.last_attribute());
}
+#ifdef PUGIXML_HAS_STRING_VIEW
+TEST_XML(dom_node_attribute_stringview, "")
+{
+ CHECK(xml_node().attribute(string_view_t(STR("a"))) == xml_attribute());
+
+ xml_node node = doc.child(string_view_t(STR("node")));
+
+ CHECK(node.attribute(string_view_t()) == xml_attribute());
+ CHECK(node.attribute(string_view_t(STR("n"))) == xml_attribute());
+ CHECK_NAME_VALUE(node.attribute(string_view_t(STR("attr1"))), STR("attr1"), STR("0"));
+ CHECK(node.attribute(string_view_t(STR("attr2"))) == node.last_attribute());
+
+ // verify only the characters in the view of the string view are included in the comparison
+ CHECK_NAME_VALUE(node.attribute(string_view_t(STR("attr1_andextratext"), 5)), STR("attr1"), STR("0"));
+ CHECK(node.attribute(string_view_t(STR("attr1"), 2)) == xml_attribute());
+}
+
+TEST_XML(dom_node_attribute_interior_null, "")
+{
+ xml_node node = doc.child(STR("node"));
+ CHECK_NAME_VALUE(node, STR("node"), STR(""));
+
+ const char_t name[] = STR("attr2\0extra");
+ size_t len = (sizeof(name) / sizeof(char_t)) - 1;
+ CHECK(len == 11);
+ CHECK_NAME_VALUE(node.attribute(string_view_t(name, 5)), STR("attr2"), STR("1")); // "attr2" view excluding null
+ CHECK(node.attribute(string_view_t(name, 6)) == xml_attribute()); // "attr2\0" view including null
+ CHECK(node.attribute(string_view_t(name, len)) == xml_attribute()); // "attr2\0extra" view
+
+ xml_attribute attr = node.attribute(STR("attr2"));
+ CHECK_NAME_VALUE(attr, STR("attr2"), STR("1"));
+ attr.set_name(string_view_t(name, len));
+
+ CHECK_NODE(doc, STR(""));
+ CHECK_NAME_VALUE(node.attribute(string_view_t(name, 5)), STR("attr2"), STR("1")); // "attr2" view excluding null
+ CHECK(node.attribute(string_view_t(name, 6)) == xml_attribute()); // "attr2\0" view including null
+ CHECK(node.attribute(string_view_t(name, len)) == xml_attribute()); // "attr2\0extra" view
+}
+#endif
+
TEST_XML(dom_node_next_previous_sibling, "")
{
CHECK(xml_node().next_sibling() == xml_node());
@@ -567,9 +643,17 @@ TEST_XML(dom_node_next_previous_sibling, "value1value2value4")
@@ -1166,6 +1250,64 @@ TEST_XML(dom_node_attribute_hinted, "")
CHECK(!node.attribute(STR("attr"), hint) && hint == attr2);
}
+#ifdef PUGIXML_HAS_STRING_VIEW
+TEST_XML(dom_node_attribute_hinted_stringview, "")
+{
+ xml_node node = doc.first_child();
+ string_view_t a1name = string_view_t(STR("attr1"));
+ string_view_t a2name = string_view_t(STR("attr2"));
+ string_view_t a3name = string_view_t(STR("attr3"));
+ xml_attribute attr1 = node.attribute(a1name);
+ xml_attribute attr2 = node.attribute(a2name);
+ xml_attribute attr3 = node.attribute(a3name);
+
+ xml_attribute hint;
+ CHECK(!xml_node().attribute(string_view_t(string_view_t(STR("test"))), hint) && !hint);
+
+ CHECK(node.attribute(a2name, hint) == attr2 && hint == attr3);
+ CHECK(node.attribute(a3name, hint) == attr3 && !hint);
+
+ CHECK(node.attribute(a1name, hint) == attr1 && hint == attr2);
+ CHECK(node.attribute(a2name, hint) == attr2 && hint == attr3);
+ CHECK(node.attribute(a1name, hint) == attr1 && hint == attr2);
+ CHECK(node.attribute(a1name, hint) == attr1 && hint == attr2);
+
+ CHECK(!node.attribute(string_view_t(), hint) && hint == attr2);
+ CHECK(!node.attribute(string_view_t(STR("attr1"), 4), hint) && hint == attr2); // "attr"
+ CHECK(node.attribute(string_view_t(STR("attr3_extra"), 5), hint) == attr3 && !hint); // "attr3"
+}
+
+TEST_XML(dom_node_attribute_hint_interior_null, "")
+{
+ xml_node node = doc.first_child();
+
+ xml_attribute attr1 = node.attribute(STR("attr1"));
+ xml_attribute attr2 = node.attribute(STR("attr2"));
+ xml_attribute attr3 = node.attribute(STR("attr3"));
+
+ CHECK(node && attr1 && attr2 && attr3);
+
+ const char_t name[] = STR("attr2\0extra");
+ size_t len = (sizeof(name) / sizeof(char_t)) - 1;
+ CHECK(len == 11);
+
+ xml_attribute hint;
+ CHECK(node.attribute(string_view_t(name, 5), hint) == attr2 && hint == attr3); // "attr2"
+ CHECK(node.attribute(string_view_t(name, 5), hint) == attr2 && hint == attr3); // "attr2"
+
+ CHECK(!node.attribute(string_view_t(name, 6), hint) && hint == attr3); // "attr2\0"
+ CHECK(!node.attribute(string_view_t(name, len), hint) && hint == attr3); // "attr2\0extra"
+
+ attr2.set_name(string_view_t(name, len)); // attr2\0extra
+
+ CHECK(node.attribute(string_view_t(name, 5), hint) == attr2 && hint == attr3); // "attr2"
+ CHECK(node.attribute(string_view_t(name, 5), hint) == attr2 && hint == attr3); // "attr2"
+
+ CHECK(!node.attribute(string_view_t(name, 6), hint) && hint == attr3); // "attr2\0"
+ CHECK(!node.attribute(string_view_t(name, len), hint) && hint == attr3); // "attr2\0extra"
+}
+#endif
+
TEST_XML(dom_as_int_overflow, "")
{
xml_node node = doc.child(STR("node"));
@@ -1302,3 +1444,35 @@ TEST(dom_node_anonymous)
CHECK_STRING(doc.child_value(), STR(""));
CHECK_STRING(doc.last_child().child_value(), STR(""));
}
+
+TEST_XML(dom_node_anonymous_child, "")
+{
+ xml_node node = doc.child(STR("node"));
+ CHECK_NAME_VALUE(node, STR("node"), STR(""));
+ node.set_name(STR(""));
+ CHECK_NODE(doc, STR("<:anonymous/>"));
+ CHECK(doc.first_child() != xml_node());
+ CHECK_NAME_VALUE(doc.first_child(), STR(""), STR(""));
+
+ // searching for empty string does not find a node with empty name
+ CHECK(doc.child(STR("")) == xml_node());
+#ifdef PUGIXML_HAS_STRING_VIEW
+ CHECK(doc.child(string_view_t()) == xml_node());
+ CHECK(doc.child(string_view_t(STR("hi"), 0)) == xml_node());
+#endif
+}
+
+TEST_XML(dom_node_anonymous_attribute, "")
+{
+ xml_attribute attr = doc.first_child().attribute(STR("attr"));
+ CHECK(attr != xml_attribute());
+ attr.set_name(STR(""));
+ CHECK_NODE(doc, STR(""));
+ CHECK_NAME_VALUE(doc.first_child().first_attribute(), STR(""), STR("0"));
+
+ CHECK(doc.first_child().attribute(STR("")) == xml_attribute());
+#ifdef PUGIXML_HAS_STRING_VIEW
+ CHECK(doc.first_child().attribute(string_view_t()) == xml_attribute());
+ CHECK(doc.first_child().attribute(string_view_t(STR("hi"), 0)) == xml_attribute());
+#endif
+}