Reputation: 9828
I have a function that scans for img
tags in a string using DOMDocument and wraps them in a div
.
$str = 'string containing HTML';
$doc = new DOMDocument();
$doc->loadHtml(mb_convert_encoding($str, 'HTML-ENTITIES', 'UTF-8'));
$tags = $doc->getElementsByTagName('img');
foreach ($tags as $tag) {
$div = $doc->createElement('div');
$tag->parentNode->insertBefore($div, $tag);
$div->appendChild($tag);
}
return $str;
However, when an img
is wrapped in a
tags, the a
tags are removed and 'replaced' with the div
. How can I keep the a
tags?
Currently,
<a href="http://google.com"><img src="srctoimg"/></a>
results in;
<div><img src="srctoimg"/></div>
rather than;
<div><a href="http://google.com"><img src="srctoimg"/></a></div>
Is there a 'wildcard' I can pass in with the second argument to insertBefore()
or how can I achieve this?
Upvotes: 2
Views: 1280
Reputation: 3701
You can do this with an XPath query.
'//*[img/parent::a or (self::img and not(parent::a))]'
This will get the parent for any img
tag that has an a
parent, as well as any image tag itself for any img
tag that does not have an immediate a
parent.
This way you don't have to change the code within your loop.
$str = <<<EOS
<html>
<body>
Image with link:
<a href="http://google.com">
<img src="srctoimg"/>
</a>
Image without link:
<img src="srctoimg"/>
</body>
</html>
EOS;
$doc = new DOMDocument();
$doc->loadHtml(mb_convert_encoding($str, 'HTML-ENTITIES', 'UTF-8'));
$xpath = new DOMXPath($doc);
$tags = $xpath->query(
'//*[img/parent::a or (self::img and not(parent::a))]'
);
foreach ($tags as $tag) {
$div = $doc->createElement('div');
$tag->parentNode->insertBefore($div, $tag);
$div->appendChild($tag);
}
echo $doc->saveHTML();
Output (indented for clarity):
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
<body>
Image with link:
<div>
<a href="http://google.com">
<img src="srctoimg">
</a>
</div>
Image without link:
<div>
<img src="srctoimg">
</div>
</body>
</html>
Upvotes: 4
Reputation: 22532
Hi I provide this solution using jquery. I know you ask this question in php.
<a href="http://google.com"><img src="srctoimg"/></a>
<script src="http://code.jquery.com/jquery-1.11.2.min.js"></script>
<script>
$('a').replaceWith(function(){
return $('<div/>', {
html: this.innerHTML
})
})
</script>
Upvotes: 0
Reputation: 757
Try with this inside your foreach
$parent = $tag->parentNode;
if( $parent->tagName == 'a' )
{
$parent->parentNode->insertBefore($div, $parent);
$div->appendChild($parent);
}
else
{
$tag->parentNode->insertBefore($div, $tag);
$div->appendChild($tag);
}
Upvotes: 2
Reputation:
Using xpath
$str = 'string containing HTML';
$doc = new DOMDocument();
$doc->loadHtml(mb_convert_encoding($str, 'HTML-ENTITIES', 'UTF-8'));
$xpath = new DOMXPath($doc);
$tags0 = $xpath->query('//a/img'); // get all <img> in <a> tag
$tags1 = $xpath->query('//img[not(parent::a)]'); // get all <img> except those with parent <a> tag
$tags = array_merge($tags0,$tags1); // merge the 2 arrays
foreach ($tags as $tag) {
$div = $doc->createElement('div');
$tag->parentNode->insertBefore($div, $tag);
$div->appendChild($tag);
}
return $str;
Upvotes: 1
Reputation: 1473
It might be simplest to just use an if
clause:
foreach ($tags as $tag) {
$div = $doc->createElement('div');
$x = $tag->parentNode;
// Parent node is not 'a': insert before <img>
if($tag->parentNode->tag != 'a') {
$tag->parentNode->insertBefore($div, $tag);
}
// Parent node is 'a': insert before <a>
else{
$tag->parentNode->parentNode->insertBefore($div, $tag);
}
$div->appendChild($tag);
}
Upvotes: 1