Fix bug #54382 (getAttributeNodeNS doesn't get xmlns* attributes)
authorArnout Boks <arnoutboks@gmail.com>
Wed, 25 Jan 2017 20:09:03 +0000 (21:09 +0100)
committerJoe Watkins <krakjoe@php.net>
Wed, 25 Jan 2017 20:59:25 +0000 (20:59 +0000)
The fix is based on the same strategy for handling namespace
declarations as used by getAttributeNode. Note that this strategy makes
these methods not return a DOMAttr for xmlns* attributes, but an
instance of the (undocumented) class DOMNameSpaceNode. This is not
really ideal, but at least this fix makes the behavior of
getAttributeNode and getAttributeNodeNS consistent.

A follow-up action would be to investigate whether DOMNameSpaceNode can
be made into a subclass of DOMAttr (which may be hard due to the way
libxml treats namespace declarations) or document this deviating return
value for xmlns* attributes.

ext/dom/element.c

index d9fa38171746535673c1202878c23d7128d08fe5..df841b6b8a52cc9535d2a2a8ac31b77d4de51abe 100644 (file)
@@ -921,7 +921,7 @@ Since: DOM Level 2
 PHP_FUNCTION(dom_element_get_attribute_node_ns)
 {
        zval *id;
-       xmlNodePtr elemp;
+       xmlNodePtr elemp, fakeAttrp;
        xmlAttrPtr attrp;
        dom_object *intern;
        size_t uri_len, name_len;
@@ -937,10 +937,34 @@ PHP_FUNCTION(dom_element_get_attribute_node_ns)
        attrp = xmlHasNsProp(elemp, (xmlChar *)name, (xmlChar *)uri);
 
        if (attrp == NULL) {
-               RETURN_NULL();
-       }
+               if (xmlStrEqual((xmlChar *) uri, (xmlChar *)DOM_XMLNS_NAMESPACE)) {
+                       xmlNsPtr nsptr;
+                       nsptr = dom_get_nsdecl(elemp, (xmlChar *)name);
+                       if (nsptr != NULL) {
+                               xmlNsPtr curns;
+                               curns = xmlNewNs(NULL, nsptr->href, NULL);
+                               if (nsptr->prefix) {
+                                       curns->prefix = xmlStrdup((xmlChar *) nsptr->prefix);
+                               }
+                               if (nsptr->prefix) {
+                                       fakeAttrp = xmlNewDocNode(elemp->doc, NULL, (xmlChar *) nsptr->prefix, nsptr->href);
+                               } else {
+                                       fakeAttrp = xmlNewDocNode(elemp->doc, NULL, (xmlChar *)"xmlns", nsptr->href);
+                               }
+                               fakeAttrp->type = XML_NAMESPACE_DECL;
+                               fakeAttrp->parent = elemp;
+                               fakeAttrp->ns = curns;
 
-       DOM_RET_OBJ((xmlNodePtr) attrp, &ret, intern);
+                               DOM_RET_OBJ(fakeAttrp, &ret, intern);
+                       } else {
+                               RETURN_NULL();
+                       }
+               } else {
+                  RETURN_NULL();
+               }
+       } else {
+               DOM_RET_OBJ((xmlNodePtr) attrp, &ret, intern);
+       }
 
 }
 /* }}} end dom_element_get_attribute_node_ns */