@@ -1104,8 +1104,9 @@ static void php_dom_transfer_document_ref(xmlNodePtr node, php_libxml_ref_obj *n
1104
1104
}
1105
1105
}
1106
1106
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
1109
1110
static xmlChar * libxml_copy_dicted_string (xmlDictPtr src_dict , xmlDictPtr dst_dict , xmlChar * str )
1110
1111
{
1111
1112
if (str == NULL ) {
@@ -1122,30 +1123,43 @@ static xmlChar *libxml_copy_dicted_string(xmlDictPtr src_dict, xmlDictPtr dst_di
1122
1123
1123
1124
static void libxml_fixup_name_and_content (xmlDocPtr src_doc , xmlDocPtr dst_doc , xmlNodePtr node )
1124
1125
{
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 );
1126
1131
node -> name = libxml_copy_dicted_string (src_doc -> dict , dst_doc -> dict , BAD_CAST node -> name );
1127
1132
node -> content = libxml_copy_dicted_string (src_doc -> dict , NULL , node -> content );
1128
1133
}
1129
1134
}
1130
1135
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 )
1132
1137
{
1133
1138
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
+ }
1136
1147
}
1137
1148
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
+ }
1140
1153
}
1141
1154
}
1142
1155
#endif
1143
1156
1144
1157
bool php_dom_adopt_node (xmlNodePtr nodep , dom_object * dom_object_new_document , xmlDocPtr new_document )
1145
1158
{
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 ) {
1149
1163
php_libxml_invalidate_node_list_cache (dom_object_new_document -> document );
1150
1164
1151
1165
/* 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
1155
1169
xmlSetTreeDoc (nodep , new_document );
1156
1170
php_dom_libxml_ns_mapper * ns_mapper = php_dom_get_ns_mapper (dom_object_new_document );
1157
1171
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
1161
1172
} 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 );
1163
1174
if (UNEXPECTED (ret != 0 )) {
1164
1175
return false;
1165
1176
}
1166
1177
}
1167
1178
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
+
1168
1184
php_dom_transfer_document_ref (nodep , dom_object_new_document -> document );
1169
1185
} else {
1170
1186
xmlUnlinkNode (nodep );
0 commit comments