Skip to content

Commit 5d5e6b0

Browse files
committed
Merge branch 'PHP-8.2'
* PHP-8.2: Fix viable next sibling search for replaceWith
2 parents 3e315df + 87148f6 commit 5d5e6b0

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

ext/dom/parentnode.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -547,27 +547,47 @@ void dom_child_node_remove(dom_object *context)
547547

548548
void dom_child_replace_with(dom_object *context, zval *nodes, uint32_t nodesc)
549549
{
550+
/* Spec link: https://dom.spec.whatwg.org/#dom-childnode-replacewith */
551+
550552
xmlNodePtr child = dom_object_get_node(context);
553+
554+
/* Spec step 1 */
551555
xmlNodePtr parentNode = child->parent;
556+
/* Spec step 2 */
557+
if (!parentNode) {
558+
int stricterror = dom_get_strict_error(context->document);
559+
php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror);
560+
return;
561+
}
552562

553563
int stricterror = dom_get_strict_error(context->document);
554564
if (UNEXPECTED(dom_child_removal_preconditions(child, stricterror) != SUCCESS)) {
555565
return;
556566
}
557567

558-
php_libxml_invalidate_node_list_cache_from_doc(context->document->ptr);
559-
560-
xmlNodePtr insertion_point = child->next;
568+
/* Spec step 3: find first following child not in nodes; otherwise null */
569+
xmlNodePtr viable_next_sibling = child->next;
570+
while (viable_next_sibling) {
571+
if (!dom_is_node_in_list(nodes, nodesc, viable_next_sibling)) {
572+
break;
573+
}
574+
viable_next_sibling = viable_next_sibling->next;
575+
}
561576

562577
if (UNEXPECTED(dom_sanity_check_node_list_for_insertion(context->document, parentNode, nodes, nodesc) != SUCCESS)) {
563578
return;
564579
}
565580

581+
php_libxml_invalidate_node_list_cache_from_doc(context->document->ptr);
582+
583+
/* Spec step 4: convert nodes into fragment */
566584
xmlNodePtr fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
567585
if (UNEXPECTED(fragment == NULL)) {
568586
return;
569587
}
570588

589+
/* Spec step 5: perform the replacement */
590+
571591
xmlNodePtr newchild = fragment->children;
572592
xmlDocPtr doc = parentNode->doc;
573593

@@ -580,7 +600,7 @@ void dom_child_replace_with(dom_object *context, zval *nodes, uint32_t nodesc)
580600
if (newchild) {
581601
xmlNodePtr last = fragment->last;
582602

583-
dom_pre_insert(insertion_point, parentNode, newchild, fragment);
603+
dom_pre_insert(viable_next_sibling, parentNode, newchild, fragment);
584604

585605
dom_fragment_assign_parent_node(parentNode, fragment);
586606
dom_reconcile_ns_list(doc, newchild, last);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
replaceWith() with a non-viable next sibling
3+
--EXTENSIONS--
4+
dom
5+
--FILE--
6+
<?php
7+
$doc = new DOMDocument;
8+
$doc->loadXML(<<<XML
9+
<?xml version="1.0"?>
10+
<container>
11+
<child>
12+
<alone/>
13+
</child>
14+
</container>
15+
XML);
16+
17+
$container = $doc->documentElement;
18+
$child = $container->firstElementChild;
19+
$alone = $child->firstElementChild;
20+
21+
$child->after($alone);
22+
echo $doc->saveXML();
23+
$child->replaceWith($alone);
24+
echo $doc->saveXML();
25+
?>
26+
--EXPECT--
27+
<?xml version="1.0"?>
28+
<container>
29+
<child>
30+
31+
</child><alone/>
32+
</container>
33+
<?xml version="1.0"?>
34+
<container>
35+
<alone/>
36+
</container>

0 commit comments

Comments
 (0)