Skip to content

Commit c174ebf

Browse files
committed
Revert "Fix phpGH-11404: DOMDocument::savexml and friends ommit xmlns="" declaration for null namespace, creating incorrect xml representation of the DOM"
This reverts commit 7eb3e9c. Although the fix follows the spec, it causes issues because a lot of old code assumes the incorrect behaviour PHP had since a long time. We cannot do this yet, especially not in a stable release. We revert this for the time being. See phpGH-11428.
1 parent 9f7d888 commit c174ebf

File tree

7 files changed

+10
-216
lines changed

7 files changed

+10
-216
lines changed

Diff for: NEWS

-2
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ PHP NEWS
3838
. Fix "invalid state error" with cloned namespace declarations. (nielsdos)
3939
. Fixed bug #55294 and #47530 and #47847 (various namespace reconciliation
4040
issues). (nielsdos)
41-
. Fixed bug GH-11404 (DOMDocument::saveXML and friends omit xmlns=""
42-
declaration for null namespace). (nielsdos)
4341
. Fixed bug #80332 (Completely broken array access functionality with
4442
DOMNamedNodeMap). (nielsdos)
4543

Diff for: ext/dom/document.c

-4
Original file line numberDiff line numberDiff line change
@@ -878,10 +878,6 @@ PHP_METHOD(DOMDocument, createElementNS)
878878

879879
if (errorcode == 0) {
880880
if (xmlValidateName((xmlChar *) localname, 0) == 0) {
881-
/* https://dom.spec.whatwg.org/#validate-and-extract: demands us to set an empty string uri to NULL */
882-
if (uri_len == 0) {
883-
uri = NULL;
884-
}
885881
nodep = xmlNewDocNode(docp, NULL, (xmlChar *) localname, (xmlChar *) value);
886882
if (nodep != NULL && uri != NULL) {
887883
nsptr = xmlSearchNsByHref(nodep->doc, nodep, (xmlChar *) uri);

Diff for: ext/dom/element.c

-4
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,6 @@ PHP_METHOD(DOMElement, __construct)
5656
if (uri_len > 0) {
5757
errorcode = dom_check_qname(name, &localname, &prefix, uri_len, name_len);
5858
if (errorcode == 0) {
59-
/* https://dom.spec.whatwg.org/#validate-and-extract: demands us to set an empty string uri to NULL */
60-
if (uri_len == 0) {
61-
uri = NULL;
62-
}
6359
nodep = xmlNewNode (NULL, (xmlChar *)localname);
6460
if (nodep != NULL && uri != NULL) {
6561
nsptr = dom_get_ns(nodep, uri, &errorcode, prefix);

Diff for: ext/dom/node.c

+9-7
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ Since: DOM Level 2
531531
int dom_node_namespace_uri_read(dom_object *obj, zval *retval)
532532
{
533533
xmlNode *nodep = dom_object_get_node(obj);
534+
char *str = NULL;
534535

535536
if (nodep == NULL) {
536537
php_dom_throw_error(INVALID_STATE_ERR, 1);
@@ -542,19 +543,20 @@ int dom_node_namespace_uri_read(dom_object *obj, zval *retval)
542543
case XML_ATTRIBUTE_NODE:
543544
case XML_NAMESPACE_DECL:
544545
if (nodep->ns != NULL) {
545-
char *str = (char *) nodep->ns->href;
546-
/* https://dom.spec.whatwg.org/#concept-attribute: namespaceUri is "null or a non-empty string" */
547-
if (str != NULL && str[0] != '\0') {
548-
ZVAL_STRING(retval, str);
549-
return SUCCESS;
550-
}
546+
str = (char *) nodep->ns->href;
551547
}
552548
break;
553549
default:
550+
str = NULL;
554551
break;
555552
}
556553

557-
ZVAL_NULL(retval);
554+
if (str != NULL) {
555+
ZVAL_STRING(retval, str);
556+
} else {
557+
ZVAL_NULL(retval);
558+
}
559+
558560
return SUCCESS;
559561
}
560562

Diff for: ext/dom/php_dom.c

-38
Original file line numberDiff line numberDiff line change
@@ -1496,33 +1496,13 @@ static void dom_libxml_reconcile_ensure_namespaces_are_declared(xmlNodePtr nodep
14961496
xmlDOMWrapReconcileNamespaces(&dummy_ctxt, nodep, /* options */ 0);
14971497
}
14981498

1499-
static bool dom_must_replace_namespace_by_empty_default(xmlDocPtr doc, xmlNodePtr nodep)
1500-
{
1501-
xmlNsPtr default_ns = xmlSearchNs(doc, nodep->parent, NULL);
1502-
return default_ns != NULL && default_ns->href != NULL && default_ns->href[0] != '\0';
1503-
}
1504-
1505-
static void dom_replace_namespace_by_empty_default(xmlDocPtr doc, xmlNodePtr nodep)
1506-
{
1507-
ZEND_ASSERT(nodep->ns == NULL);
1508-
/* The node uses the default empty namespace, but the current default namespace is non-empty.
1509-
* We can't unconditionally do this because otherwise libxml2 creates an xmlns="" declaration.
1510-
* Note: there's no point searching the oldNs list, because we haven't found it in the tree anyway.
1511-
* Ideally this would be pre-allocated but unfortunately libxml2 doesn't offer such a functionality. */
1512-
xmlSetNs(nodep, xmlNewNs(nodep, (const xmlChar *) "", NULL));
1513-
}
1514-
15151499
void dom_reconcile_ns(xmlDocPtr doc, xmlNodePtr nodep) /* {{{ */
15161500
{
15171501
/* Although the node type will be checked by the libxml2 API,
15181502
* we still want to do the internal reconciliation conditionally. */
15191503
if (nodep->type == XML_ELEMENT_NODE) {
15201504
dom_reconcile_ns_internal(doc, nodep, nodep->parent);
15211505
dom_libxml_reconcile_ensure_namespaces_are_declared(nodep);
1522-
/* Check nodep->ns first to avoid an expensive lookup. */
1523-
if (nodep->ns == NULL && dom_must_replace_namespace_by_empty_default(doc, nodep)) {
1524-
dom_replace_namespace_by_empty_default(doc, nodep);
1525-
}
15261506
}
15271507
}
15281508
/* }}} */
@@ -1546,30 +1526,12 @@ static void dom_reconcile_ns_list_internal(xmlDocPtr doc, xmlNodePtr nodep, xmlN
15461526

15471527
void dom_reconcile_ns_list(xmlDocPtr doc, xmlNodePtr nodep, xmlNodePtr last)
15481528
{
1549-
bool did_compute_must_replace_namespace_by_empty_default = false;
1550-
bool must_replace_namespace_by_empty_default = false;
1551-
15521529
dom_reconcile_ns_list_internal(doc, nodep, last, nodep->parent);
1553-
15541530
/* The loop is outside of the recursion in the above call because
15551531
* dom_libxml_reconcile_ensure_namespaces_are_declared() performs its own recursion. */
15561532
while (true) {
15571533
/* The internal libxml2 call will already check the node type, no need for us to do it here. */
15581534
dom_libxml_reconcile_ensure_namespaces_are_declared(nodep);
1559-
1560-
/* We don't have to handle the children, because if their ns's are NULL they'll just take on the default
1561-
* which should've been reconciled before. */
1562-
if (nodep->ns == NULL) {
1563-
/* This is an optimistic approach: we assume that most of the time we don't need the result of the computation. */
1564-
if (!did_compute_must_replace_namespace_by_empty_default) {
1565-
did_compute_must_replace_namespace_by_empty_default = true;
1566-
must_replace_namespace_by_empty_default = dom_must_replace_namespace_by_empty_default(doc, nodep);
1567-
}
1568-
if (must_replace_namespace_by_empty_default) {
1569-
dom_replace_namespace_by_empty_default(doc, nodep);
1570-
}
1571-
}
1572-
15731535
if (nodep == last) {
15741536
break;
15751537
}

Diff for: ext/dom/tests/bug47530.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ test_appendChild_with_shadowing();
121121
<html xmlns="https://php.net/something" xmlns:ns="https://php.net/whatever"><element ns:foo="https://php.net/bar"/></html>
122122
-- Test document fragment without import --
123123
<?xml version="1.0"?>
124-
<html xmlns=""><element xmlns:foo="https://php.net/bar"><foo:bar/><bar/></element></html>
124+
<html xmlns=""><element xmlns:foo="https://php.net/bar"><foo:bar/><bar xmlns=""/></element></html>
125125
string(7) "foo:bar"
126126
string(19) "https://php.net/bar"
127127
-- Test document import --

Diff for: ext/dom/tests/gh11404.phpt

-160
This file was deleted.

0 commit comments

Comments
 (0)