Skip to content

Commit 62ef7bb

Browse files
committed
Merge branch 'PHP-8.2'
* PHP-8.2: Handle fragments consisting out of multiple children without a single root correctly
2 parents f04e505 + f2ed2b8 commit 62ef7bb

File tree

2 files changed

+53
-15
lines changed

2 files changed

+53
-15
lines changed

ext/dom/parentnode.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -182,15 +182,7 @@ xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNod
182182
goto err;
183183
}
184184

185-
if (newNode->type == XML_DOCUMENT_FRAG_NODE) {
186-
/* Unpack document fragment nodes, the behaviour differs for different libxml2 versions. */
187-
newNode = newNode->children;
188-
if (UNEXPECTED(newNode == NULL)) {
189-
/* No nodes to add, nothing to do here */
190-
continue;
191-
}
192-
xmlUnlinkNode(newNode);
193-
} else if (newNode->parent != NULL) {
185+
if (newNode->parent != NULL) {
194186
xmlUnlinkNode(newNode);
195187
}
196188

@@ -209,14 +201,23 @@ xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNod
209201
newNode = xmlCopyNode(newNode, 1);
210202
}
211203

212-
if (!xmlAddChild(fragment, newNode)) {
204+
if (newNode->type == XML_DOCUMENT_FRAG_NODE) {
205+
/* Unpack document fragment nodes, the behaviour differs for different libxml2 versions. */
206+
newNode = newNode->children;
207+
while (newNode) {
208+
xmlNodePtr next = newNode->next;
209+
xmlUnlinkNode(newNode);
210+
if (!xmlAddChild(fragment, newNode)) {
211+
goto hierarchy_request_err;
212+
}
213+
newNode = next;
214+
}
215+
} else if (!xmlAddChild(fragment, newNode)) {
213216
if (will_free) {
214217
xmlFreeNode(newNode);
215218
}
216219
goto hierarchy_request_err;
217220
}
218-
219-
continue;
220221
} else {
221222
zend_argument_type_error(i + 1, "must be of type DOMNode|string, %s given", zend_zval_value_name(&nodes[i]));
222223
goto err;
@@ -364,14 +365,13 @@ static void dom_pre_insert(xmlNodePtr insertion_point, xmlNodePtr parentNode, xm
364365
/* Place it as last node */
365366
if (parentNode->children) {
366367
/* There are children */
367-
fragment->last->prev = parentNode->last;
368-
newchild->prev = parentNode->last->prev;
368+
newchild->prev = parentNode->last;
369369
parentNode->last->next = newchild;
370370
} else {
371371
/* No children, because they moved out when they became a fragment */
372372
parentNode->children = newchild;
373-
parentNode->last = newchild;
374373
}
374+
parentNode->last = fragment->last;
375375
} else {
376376
/* Insert fragment before insertion_point */
377377
fragment->last->next = insertion_point;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
Handling fragments of multiple nodes for DOMParentNode
3+
--EXTENSIONS--
4+
dom
5+
--FILE--
6+
<?php
7+
8+
$dom = new DOMDocument();
9+
$dom->loadXML('<!DOCTYPE HTML><html><container/></html>');
10+
11+
$container = $dom->documentElement->firstElementChild;
12+
13+
$fragment = $dom->createDocumentFragment();
14+
$fragment->appendChild($dom->createElement('p', '1'));
15+
$fragment->appendChild($dom->createElement('b', '2'));
16+
$container->replaceWith($fragment);
17+
echo $dom->saveXML();
18+
19+
$dom->documentElement->append('foo');
20+
echo $dom->saveXML();
21+
22+
$fragment = $dom->createDocumentFragment();
23+
$fragment->appendChild($dom->createElement('p', '3'));
24+
$fragment->appendChild($dom->createElement('b', '4'));
25+
$dom->documentElement->prepend($fragment);
26+
echo $dom->saveXML();
27+
28+
?>
29+
--EXPECT--
30+
<?xml version="1.0"?>
31+
<!DOCTYPE HTML>
32+
<html><p>1</p><b>2</b></html>
33+
<?xml version="1.0"?>
34+
<!DOCTYPE HTML>
35+
<html><p>1</p><b>2</b>foo</html>
36+
<?xml version="1.0"?>
37+
<!DOCTYPE HTML>
38+
<html><p>3</p><b>4</b><p>1</p><b>2</b>foo</html>

0 commit comments

Comments
 (0)