php-html-parser
php-html-parser copied to clipboard
[Request] Is it possible to replace an element with another one?
Hi,
First of all, great project! It's super easy to use and works brilliantly. It really made my life easier.
Is it possible to replace an element with another one? Or maybe being able to know the position of an element, so once deleted, you would be able to put another element in its place.
for example replace:
<div id="foo"><p class="bar"><img src="http://something.com/image.jpg><p></div>
with:
<img src="http://something.com/image.jpg>
Thanks
@mightymess did you manage to get this working?
@felixsanz unfortunately I couldn't make this work. I tried using replaceChild but that relied on having a consistent html structure and the page I working with is a mess.
It's possible with a hack, see: https://github.com/paquettg/php-html-parser/issues/125#issuecomment-366585412
Its not working
There are a few ways I've found. You mention the page structure being a mess but if you can find a way to select the item to replace and the replacement you should be good.
Given a very consistent hierarchy, you can take the element you want and go up the parents till you have the one you want to replace:
$dom = new Dom;
$input = '<div id="foo"><p class="bar"><img src="http://something.com/image.jpg"><p></div>';
$dom->load($input);
$imgs = $dom->find('img');
foreach($imgs as $img){
$parent = $img->getParent();
$grandParent = $parent->getParent();
$greatGrandParent = $grandParent->getParent();
$greatGrandParent->replaceChild($grandParent->id(),$img);
}
echo "\r\ninput: " . $input;
echo "\r\noutput: " . $dom->innerHtml;
Or, similarly, if you know the id of the item you want to replace you can just get its parent and replace that.
...
$replaceMe = $dom->find('#foo');
$replaceMeParent = $replaceMe->getParent();
$replaceMeParent->replaceChild($replaceMe->id(),$img);
...
Another direction is to go down the tree with getChildren. For instance, if you want to replace all links with their text (why I'm here), see below. Note the need to recursively replace items as $child->text doesn't work like jQuery's $element.text() and there may be things like span or other elements within the link.
function fixTextRecursive($linkyText){
if(!$linkyText->isTextNode()){
$children = $linkyText->getChildren();
foreach($children as $child){
fixTextRecursive($child);
if($child->tag->name() == 'a'){
$replacement = new TextNode($child->text);
$linkyText->replaceChild($child->id(), $replacement);
}
}
}
}
fixTextRecursive($input);
This worked for me:
$dom = new Dom;
$dom->loadStr('<div id="foo"><p class="bar"><img src="http://something.com/image.jpg"><p></div>');
$div_foo = $dom->find('div#foo')[0];
$src = $div_foo->find('img')->src;
foreach ($div_foo->getChildren() as $children) {
$children->delete();
}
$div_foo->setTag('img');
$div_foo->getTag()->selfClosing();
$div_foo->getTag()->setAttribute('src', $src);
echo $dom;