php-html-parser icon indicating copy to clipboard operation
php-html-parser copied to clipboard

[Request] Is it possible to replace an element with another one?

Open mightymess opened this issue 8 years ago • 6 comments

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 avatar Sep 20 '17 12:09 mightymess

@mightymess did you manage to get this working?

felixsanz avatar Oct 09 '17 19:10 felixsanz

@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.

mightymess avatar Oct 12 '17 09:10 mightymess

It's possible with a hack, see: https://github.com/paquettg/php-html-parser/issues/125#issuecomment-366585412

maedi avatar Mar 01 '18 04:03 maedi

Its not working

nirajkmr avatar Aug 08 '18 10:08 nirajkmr

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);

frostbitten avatar Oct 28 '19 19:10 frostbitten

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;

AliN11 avatar Apr 30 '21 11:04 AliN11