Skip to content

Fix spec compliance error for DOMDocument::getElementsByTagNameNS #11343

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion ext/dom/php_dom.c
Original file line number Diff line number Diff line change
Expand Up @@ -1270,10 +1270,15 @@ xmlNode *dom_get_elements_by_tag_name_ns_raw(xmlNodePtr nodep, char *ns, char *l
{
xmlNodePtr ret = NULL;

/* Note: The spec says that ns == '' must be transformed to ns == NULL. In other words, they are equivalent.
* PHP however does not do this and internally uses the empty string everywhere when the user provides ns == NULL.
* This is because for PHP ns == NULL has another meaning: "match every namespace" instead of "match the empty namespace". */
bool ns_match_any = ns == NULL || (ns[0] == '*' && ns[1] == '\0');

while (nodep != NULL && (*cur <= index || index == -1)) {
if (nodep->type == XML_ELEMENT_NODE) {
if (xmlStrEqual(nodep->name, (xmlChar *)local) || xmlStrEqual((xmlChar *)"*", (xmlChar *)local)) {
if (ns == NULL || (!strcmp(ns, "") && nodep->ns == NULL) || (nodep->ns != NULL && (xmlStrEqual(nodep->ns->href, (xmlChar *)ns) || xmlStrEqual((xmlChar *)"*", (xmlChar *)ns)))) {
if (ns_match_any || (!strcmp(ns, "") && nodep->ns == NULL) || (nodep->ns != NULL && xmlStrEqual(nodep->ns->href, (xmlChar *)ns))) {
if (*cur == index) {
ret = nodep;
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
--TEST--
DOMDocument::getElementsByTagNameNS() match any namespace
--EXTENSIONS--
dom
--FILE--
<?php

/* Sample document taken from https://www.php.net/manual/en/domdocument.getelementsbytagname.php */
$xml = <<<EOD
<?xml version="1.0" ?>
<chapter xmlns:xi="http://www.w3.org/2001/XInclude">
<title>Books of the other guy..</title>
<para>
<xi:include href="book.xml">
<xi:fallback>
<error>xinclude: book.xml not found</error>
</xi:fallback>
</xi:include>
<include>
This is another namespace
</include>
</para>
</chapter>
EOD;
$dom = new DOMDocument;

// load the XML string defined above
$dom->loadXML($xml);

function test($namespace, $local) {
global $dom;
$namespace_str = $namespace !== NULL ? "'$namespace'" : "null";
echo "-- getElementsByTagNameNS($namespace_str, '$local') --\n";
foreach ($dom->getElementsByTagNameNS($namespace, $local) as $element) {
echo 'local name: ', $element->localName, ', prefix: ', $element->prefix, "\n";
}
}

// Should *also* include objects even without a namespace
test(null, '*');
// Should *also* include objects even without a namespace
test('*', '*');
// Should *only* include objects without a namespace
test('', '*');
// Should *only* include objects with the specified namespace
test('http://www.w3.org/2001/XInclude', '*');
// Should not give any output
test('', 'fallback');
// Should not give any output, because the null namespace is the same as the empty namespace
test(null, 'fallback');
// Should only output the include from the empty namespace
test(null, 'include');

?>
--EXPECT--
-- getElementsByTagNameNS(null, '*') --
local name: chapter, prefix:
local name: title, prefix:
local name: para, prefix:
local name: error, prefix:
local name: include, prefix:
-- getElementsByTagNameNS('*', '*') --
local name: chapter, prefix:
local name: title, prefix:
local name: para, prefix:
local name: include, prefix: xi
local name: fallback, prefix: xi
local name: error, prefix:
local name: include, prefix:
-- getElementsByTagNameNS('', '*') --
local name: chapter, prefix:
local name: title, prefix:
local name: para, prefix:
local name: error, prefix:
local name: include, prefix:
-- getElementsByTagNameNS('http://www.w3.org/2001/XInclude', '*') --
local name: include, prefix: xi
local name: fallback, prefix: xi
-- getElementsByTagNameNS('', 'fallback') --
-- getElementsByTagNameNS(null, 'fallback') --
-- getElementsByTagNameNS(null, 'include') --
local name: include, prefix: