@@ -1104,8 +1104,9 @@ static void php_dom_transfer_document_ref(xmlNodePtr node, php_libxml_ref_obj *n
11041104	}
11051105}
11061106
1107- /* Workaround for bug that was fixed in https://github.com/GNOME/libxml2/commit/4bc3ebf3eaba352fbbce2ef70ad00a3c7752478a */ 
1108- #if  LIBXML_VERSION  <  21000 
1107+ /* Workaround for bug that was fixed in https://github.com/GNOME/libxml2/commit/4bc3ebf3eaba352fbbce2ef70ad00a3c7752478a 
1108+  * and https://github.com/GNOME/libxml2/commit/bc7ab5a2e61e4b36accf6803c5b0e245c11154b1 */ 
1109+ #if  LIBXML_VERSION  <  21300 
11091110static  xmlChar  * libxml_copy_dicted_string (xmlDictPtr  src_dict , xmlDictPtr  dst_dict , xmlChar  * str )
11101111{
11111112	if  (str  ==  NULL ) {
@@ -1122,30 +1123,43 @@ static xmlChar *libxml_copy_dicted_string(xmlDictPtr src_dict, xmlDictPtr dst_di
11221123
11231124static  void  libxml_fixup_name_and_content (xmlDocPtr  src_doc , xmlDocPtr  dst_doc , xmlNodePtr  node )
11241125{
1125- 	if  (src_doc  !=  NULL  &&  dst_doc  !=  src_doc  &&  src_doc -> dict  !=  NULL ) {
1126+ 	if  (node -> type  ==  XML_ENTITY_REF_NODE ) {
1127+ 		node -> children  =  NULL ; /* Break link with original document. */ 
1128+ 	}
1129+ 	if  (src_doc  !=  NULL  &&  src_doc -> dict  !=  NULL ) {
1130+ 		ZEND_ASSERT (dst_doc  !=  src_doc );
11261131		node -> name  =  libxml_copy_dicted_string (src_doc -> dict , dst_doc -> dict , BAD_CAST  node -> name );
11271132		node -> content  =  libxml_copy_dicted_string (src_doc -> dict , NULL , node -> content );
11281133	}
11291134}
11301135
1131- static  void  libxml_fixup_name_and_content_element (xmlDocPtr  src_doc , xmlDocPtr  dst_doc , xmlNodePtr  node )
1136+ static  void  libxml_fixup_name_and_content_outer (xmlDocPtr  src_doc , xmlDocPtr  dst_doc , xmlNodePtr  node )
11321137{
11331138	libxml_fixup_name_and_content (src_doc , dst_doc , node );
1134- 	for  (xmlAttrPtr  attr  =  node -> properties ; attr  !=  NULL ; attr  =  attr -> next ) {
1135- 		libxml_fixup_name_and_content (src_doc , dst_doc , (xmlNodePtr ) attr );
1139+ 
1140+ 	if  (node -> type  ==  XML_ELEMENT_NODE ) {
1141+ 		for  (xmlAttrPtr  attr  =  node -> properties ; attr  !=  NULL ; attr  =  attr -> next ) {
1142+ 			libxml_fixup_name_and_content (src_doc , dst_doc , (xmlNodePtr ) attr );
1143+ 			for  (xmlNodePtr  attr_child  =  attr -> children ; attr_child  !=  NULL ; attr_child  =  attr_child -> next ) {
1144+ 				libxml_fixup_name_and_content (src_doc , dst_doc , attr_child );
1145+ 			}
1146+ 		}
11361147	}
11371148
1138- 	for  (xmlNodePtr  child  =  node -> children ; child  !=  NULL ; child  =  child -> next ) {
1139- 		libxml_fixup_name_and_content_element (src_doc , dst_doc , child );
1149+ 	if  (node -> type  ==  XML_ELEMENT_NODE  ||  node -> type  ==  XML_ATTRIBUTE_NODE ) {
1150+ 		for  (xmlNodePtr  child  =  node -> children ; child  !=  NULL ; child  =  child -> next ) {
1151+ 			libxml_fixup_name_and_content_outer (src_doc , dst_doc , child );
1152+ 		}
11401153	}
11411154}
11421155#endif 
11431156
11441157bool  php_dom_adopt_node (xmlNodePtr  nodep , dom_object  * dom_object_new_document , xmlDocPtr  new_document )
11451158{
1146- 	xmlDocPtr  original_document  =  nodep -> doc ;
1147- 	php_libxml_invalidate_node_list_cache_from_doc (original_document );
1148- 	if  (nodep -> doc  !=  new_document ) {
1159+ 	xmlDocPtr  old_doc  =  nodep -> doc ;
1160+ 
1161+ 	php_libxml_invalidate_node_list_cache_from_doc (old_doc );
1162+ 	if  (old_doc  !=  new_document ) {
11491163		php_libxml_invalidate_node_list_cache (dom_object_new_document -> document );
11501164
11511165		/* Note for ATTRIBUTE_NODE: specified is always true in ext/dom, 
@@ -1155,16 +1169,18 @@ bool php_dom_adopt_node(xmlNodePtr nodep, dom_object *dom_object_new_document, x
11551169			xmlSetTreeDoc (nodep , new_document );
11561170			php_dom_libxml_ns_mapper  * ns_mapper  =  php_dom_get_ns_mapper (dom_object_new_document );
11571171			php_dom_libxml_reconcile_modern (ns_mapper , nodep );
1158- #if  LIBXML_VERSION  <  21000 
1159- 			libxml_fixup_name_and_content_element (original_document , new_document , nodep );
1160- #endif 
11611172		} else  {
1162- 			int  ret  =  xmlDOMWrapAdoptNode (NULL , original_document , nodep , new_document , NULL , /* options, unused */  0 );
1173+ 			int  ret  =  xmlDOMWrapAdoptNode (NULL , old_doc , nodep , new_document , NULL , /* options, unused */  0 );
11631174			if  (UNEXPECTED (ret  !=  0 )) {
11641175				return  false;
11651176			}
11661177		}
11671178
1179+ #if  LIBXML_VERSION  <  21300 
1180+ 		/* Must be first before transferring the ref to ensure the old document dictionary stays alive. */ 
1181+ 		libxml_fixup_name_and_content_outer (old_doc , new_document , nodep );
1182+ #endif 
1183+ 
11681184		php_dom_transfer_document_ref (nodep , dom_object_new_document -> document );
11691185	} else  {
11701186		xmlUnlinkNode (nodep );
0 commit comments