FluentDOM
FluentDOM copied to clipboard
Cannot replace root elements in html-fragment
<p>Paragraph 1</p> <p>Paragraph 2</p><p>Paragraph 3</p>
As there is no root, how can I search the p
and replace it?
I tired to use filter
and replace
, but it will remove all my matched elements.
$dom = FluentDOM::QueryCss('<p>Paragraph 1</p> <p>Paragraph 2</p><p>Paragraph 3</p>', 'html-fragment');
$dom->filter('p')->first()->each(function($element) {
$element->replace('hi');
});
echo $dom;
Expected:
hi <p>Paragraph 2</p><p>Paragraph 3</p>
Actual:
<p>Paragraph 2</p><p>Paragraph 3</p>
If you're loading an HTML fragment the top level elements should be automatically selected. Here is a problem with replace() however.
At current implementation required the node to have a parent that is an element node. But in this case it is the document node. I added a test and a fix.
I have tried the new commit. filter
seems can search deeply.
Code:
$dom = FluentDOM::QueryCss('<div><b>5</b><p>4</p></div>', 'html-fragment');
$dom->filter('p')->each(function($element) {
$element->replace('hi');
});
echo $dom;
Expected:
<div><b>5</b><p>4</p></div>
Actual:
hi
In jquery:
var test = $("<div><b>5</b><p>4</p></div>");
test.filter("p").replaceWith('hi');
console.log(test.outerHTML());
Result:
<div><b>5</b><p>4</p></div>
And with the following Code, the result is also wrong:
$dom = FluentDOM::QueryCss('<p>Paragraph 1</p> <p>Paragraph 2</p><p>Paragraph 3</p><div><b>5</b><p>4</p></div>', 'html-fragment');
$dom->filter('p')->last()->replaceWith('hi');
echo $dom;
Expected:
<p>Paragraph 1</p> <p>Paragraph 2</p>hi<div><b>5</b><p>4</p></div>
Actual:
<p>Paragraph 1</p> <p>Paragraph 2</p><p>Paragraph 3</p>hi
filter() reduces the current selection. You're filtering the current selection for any node that is a 'p' or has a 'p' descendant. The div has a p descendant so it matches. The div is replaced.
Why don't you use find()?
But the result is different from the jquery version as I posted above.
The reason why I don't use find because I can't find the root elements.
code:
$dom = FluentDOM::QueryCss('<p>Paragraph 1</p> <p>Paragraph 2</p><p>Paragraph 3</p><div><b>5</b><p>4</p></div>', 'html-fragment');
$dom->find('p')->first()->replaceWith('hi');
echo $dom;
Result:
<p>Paragraph 1</p> <p>Paragraph 2</p><p>Paragraph 3</p><div><b>5</b>hi</div>
the first it finds is the p inside the div.
Hi, any updates?
The actual problem left seems to be with the CSS Selector to Xpath conversion. I added some tests using specific Xpath expressions and it works:
https://github.com/FluentDOM/FluentDOM/commit/a8c925b49933e88810bf6fb3d0e97005480c1767
This is difficult to debug because the conversion is not part of FluentDOM itself and an edge case. I will look into it further but it will take time.