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