@@ -2101,33 +2101,72 @@ PHP_METHOD(DOMNode, lookupNamespaceURI)
21012101}
21022102/* }}} end dom_node_lookup_namespace_uri */
21032103
2104+ /* Allocate, track and prepend a temporary nsDef entry for C14N.
2105+ * Returns the new xmlNsPtr for the caller to fill in href/prefix/_private,
2106+ * or NULL on allocation failure. */
2107+ static xmlNsPtr dom_alloc_ns_decl (HashTable * links , xmlNodePtr node )
2108+ {
2109+ xmlNsPtr ns = xmlMalloc (sizeof (* ns ));
2110+ if (!ns ) {
2111+ return NULL ;
2112+ }
2113+
2114+ zval * zv = zend_hash_index_lookup (links , (zend_ulong ) node );
2115+ if (Z_ISNULL_P (zv )) {
2116+ ZVAL_LONG (zv , 1 );
2117+ } else {
2118+ Z_LVAL_P (zv )++ ;
2119+ }
2120+
2121+ memset (ns , 0 , sizeof (* ns ));
2122+ ns -> type = XML_LOCAL_NAMESPACE ;
2123+ ns -> next = node -> nsDef ;
2124+ node -> nsDef = ns ;
2125+
2126+ return ns ;
2127+ }
2128+
2129+ /* Mint a temporary nsDef entry so C14N finds namespaces that live on node->ns
2130+ * but have no matching xmlns attribute (typical for createElementNS). */
2131+ static void dom_add_synthetic_ns_decl (HashTable * links , xmlNodePtr node , xmlNsPtr src_ns )
2132+ {
2133+ xmlNsPtr ns = dom_alloc_ns_decl (links , node );
2134+ if (!ns ) {
2135+ return ;
2136+ }
2137+
2138+ ns -> href = xmlStrdup (src_ns -> href );
2139+ ns -> prefix = src_ns -> prefix ? xmlStrdup (src_ns -> prefix ) : NULL ;
2140+ }
2141+
2142+ /* Same, but for attribute namespaces, which may collide by prefix with the
2143+ * element's own ns or with a sibling attribute's ns. */
2144+ static void dom_add_synthetic_ns_decl_for_attr (HashTable * links , xmlNodePtr node , xmlNsPtr src_ns )
2145+ {
2146+ for (xmlNsPtr existing = node -> nsDef ; existing ; existing = existing -> next ) {
2147+ if (xmlStrEqual (existing -> prefix , src_ns -> prefix )) {
2148+ return ;
2149+ }
2150+ }
2151+
2152+ dom_add_synthetic_ns_decl (links , node , src_ns );
2153+ }
2154+
21042155static void dom_relink_ns_decls_element (HashTable * links , xmlNodePtr node )
21052156{
21062157 if (node -> type == XML_ELEMENT_NODE ) {
21072158 for (xmlAttrPtr attr = node -> properties ; attr ; attr = attr -> next ) {
21082159 if (php_dom_ns_is_fast ((const xmlNode * ) attr , php_dom_ns_is_xmlns_magic_token )) {
2109- xmlNsPtr ns = xmlMalloc ( sizeof ( * ns ) );
2160+ xmlNsPtr ns = dom_alloc_ns_decl ( links , node );
21102161 if (!ns ) {
21112162 return ;
21122163 }
21132164
2114- zval * zv = zend_hash_index_lookup (links , (zend_ulong ) node );
2115- if (Z_ISNULL_P (zv )) {
2116- ZVAL_LONG (zv , 1 );
2117- } else {
2118- Z_LVAL_P (zv )++ ;
2119- }
2120-
21212165 bool should_free ;
21222166 xmlChar * attr_value = php_libxml_attr_value (attr , & should_free );
21232167
2124- memset (ns , 0 , sizeof (* ns ));
2125- ns -> type = XML_LOCAL_NAMESPACE ;
21262168 ns -> href = should_free ? attr_value : xmlStrdup (attr_value );
21272169 ns -> prefix = attr -> ns -> prefix ? xmlStrdup (attr -> name ) : NULL ;
2128- ns -> next = node -> nsDef ;
2129- node -> nsDef = ns ;
2130-
21312170 ns -> _private = attr ;
21322171 if (attr -> prev ) {
21332172 attr -> prev -> next = attr -> next ;
@@ -2148,6 +2187,14 @@ static void dom_relink_ns_decls_element(HashTable *links, xmlNodePtr node)
21482187 * can return the current namespace. */
21492188 zend_hash_index_add_new_ptr (links , (zend_ulong ) node | 1 , node -> ns );
21502189 node -> ns = xmlSearchNs (node -> doc , node , NULL );
2190+ } else if (node -> ns ) {
2191+ dom_add_synthetic_ns_decl (links , node , node -> ns );
2192+ }
2193+
2194+ for (xmlAttrPtr attr = node -> properties ; attr ; attr = attr -> next ) {
2195+ if (attr -> ns && !php_dom_ns_is_fast ((const xmlNode * ) attr , php_dom_ns_is_xmlns_magic_token )) {
2196+ dom_add_synthetic_ns_decl_for_attr (links , node , attr -> ns );
2197+ }
21512198 }
21522199 }
21532200}
@@ -2177,13 +2224,15 @@ static void dom_unlink_ns_decls(HashTable *links)
21772224 node -> nsDef = ns -> next ;
21782225
21792226 xmlAttrPtr attr = ns -> _private ;
2180- if (attr -> prev ) {
2181- attr -> prev -> next = attr ;
2182- } else {
2183- node -> properties = attr ;
2184- }
2185- if (attr -> next ) {
2186- attr -> next -> prev = attr ;
2227+ if (attr ) {
2228+ if (attr -> prev ) {
2229+ attr -> prev -> next = attr ;
2230+ } else {
2231+ node -> properties = attr ;
2232+ }
2233+ if (attr -> next ) {
2234+ attr -> next -> prev = attr ;
2235+ }
21872236 }
21882237
21892238 xmlFreeNs (ns );
0 commit comments