Skip to content

Commit df6e8bd

Browse files
committedAug 7, 2023
Fix viable next sibling search for replaceWith
Closes GH-11888.
1 parent 96885bc commit df6e8bd

File tree

2 files changed

+58
-2
lines changed

2 files changed

+58
-2
lines changed
 

‎ext/dom/parentnode.c

+22-2
Original file line numberDiff line numberDiff line change
@@ -550,25 +550,45 @@ void dom_child_node_remove(dom_object *context)
550550

551551
void dom_child_replace_with(dom_object *context, zval *nodes, int nodesc)
552552
{
553+
/* Spec link: https://dom.spec.whatwg.org/#dom-childnode-replacewith */
554+
553555
xmlNodePtr child = dom_object_get_node(context);
556+
557+
/* Spec step 1 */
554558
xmlNodePtr parentNode = child->parent;
559+
/* Spec step 2 */
560+
if (!parentNode) {
561+
int stricterror = dom_get_strict_error(context->document);
562+
php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror);
563+
return;
564+
}
555565

556566
int stricterror = dom_get_strict_error(context->document);
557567
if (UNEXPECTED(dom_child_removal_preconditions(child, stricterror) != SUCCESS)) {
558568
return;
559569
}
560570

561-
xmlNodePtr insertion_point = child->next;
571+
/* Spec step 3: find first following child not in nodes; otherwise null */
572+
xmlNodePtr viable_next_sibling = child->next;
573+
while (viable_next_sibling) {
574+
if (!dom_is_node_in_list(nodes, nodesc, viable_next_sibling)) {
575+
break;
576+
}
577+
viable_next_sibling = viable_next_sibling->next;
578+
}
562579

563580
if (UNEXPECTED(dom_sanity_check_node_list_for_insertion(context->document, parentNode, nodes, nodesc) != SUCCESS)) {
564581
return;
565582
}
566583

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

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

@@ -580,7 +600,7 @@ void dom_child_replace_with(dom_object *context, zval *nodes, int 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);
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)
Please sign in to comment.