Replace all images in HTML with text

2019-07-18 21:40发布

问题:

I am trying to replace all images in some HTML which meet specific requirements with the appropriate text. The specific requirements are that they are of class "replaceMe" and the image src filename is in $myArray. Upon searching for solutions, it appears that some sort of PHP DOM technique is appropriate, however, I am very new with this. For instance, given $html, I wish to return $desired_html. At the bottom of this post is my attempted implementation which currently doesn't work. Thank you

$myArray=array(
    'goodImgage1'=>'Replacement for Good Image 1',
    'goodImgage2'=>'Replacement for Good Image 2'
);

$html = '<div>
<p>Random text and an <img src="goodImgage1.png" alt="" class="replaceMe">.  More random text.</p>
<p>Random text and an <img src="goodImgage2.png" alt="" class="replaceMe">.  More random text.</p>
<p>Random text and an <img src="goodImgage2.png" alt="" class="dontReplaceMe">.  More random text.</p>
<p>Random text and an <img src="badImgage1.png"  alt="" class="replaceMe">.  More random text.</p>
</div>';

$desiredHtml = '<div>
<p>Random text and an Replacement for Good Image 1.  More random text.</p>
<p>Random text and an Replacement for Good Image 2.  More random text.</p>
<p>Random text and an <img src="goodImgage2.png" alt="" class="dontReplaceMe">.  More random text.</p>
<p>Random text and an <img src="badImgage1.png"  alt="" class="replaceMe">.  More random text.</p>
</div>';

Below is what I am attempting to do..

libxml_use_internal_errors(true);   //Temorarily disable errors resulting from improperly formed HTML
$doc = new DOMDocument();
$doc->loadHTML($html);

//What does this do for me?
$imgs= $doc->getElementsByTagName('img');
foreach ($imgs as $img){}

$xpath = new DOMXPath($doc);
foreach( $xpath->query( '//img') as $img) {
    if(true){   //How do I check class and image name?
        $new = $doc->createTextNode("New Attribute"); 
        $img->parentNode->replaceChild($new,$img);
    }
}

$html=$doc->saveHTML();
libxml_use_internal_errors(false);

回答1:

Do it like this, you were on a good way:

$myArray=array(
    'goodImgage1.png'=>'Replacement for Good Image 1',
    'goodImgage2.png'=>'Replacement for Good Image 2'
);

$html = '<div>
<p>Random text and an <img src="goodImgage1.png" alt="" class="replaceMe">.  More random text.</p>
<p>Random text and an <img src="goodImgage2.png" alt="" class="replaceMe">.  More random text.</p>
<p>Random text and an <img src="goodImgage2.png" alt="" class="dontReplaceMe">.  More random text.</p>
<p>Random text and an <img src="badImgage1.png"  alt="" class="replaceMe">.  More random text.</p>
</div>';

$classesToReplace = array('replaceMe');

libxml_use_internal_errors(true);   //Temorarily disable errors resulting from improperly formed HTML
$doc = new DOMDocument();
$doc->loadHTML($html);

$xpath = new DOMXPath($doc);
foreach( $xpath->query( '//img') as $img) {
    // get the classes into an array
    $classes = explode(' ', $img->getAttribute('class')); // this will contain the classes assigned to the element
    $classMatches = array_intersect($classes, $classesToReplace);

    // preprocess the image name to match the $myArray keys
    $imageName = $img->getAttribute('src');

    if (isset($myArray[$imageName]) && $classMatches) {   
        $new = $doc->createTextNode($myArray[$imageName]); 
        $img->parentNode->replaceChild($new,$img);
    }
}

echo var_dump($html = $doc->saveHTML());

Please note the following:

  • I made the code check for images that have the replaceMe class, potentially in addition to other classes
  • I added the full image file names to your $myArray keys, basically for simplicity.


回答2:

likeitlikeit was faster. I'll post my answer, though, because it has some differences in detail, e.g. xpath doing the job of selecting only <img> with the appropriate class attribute, use of pathinfo to get filename without extension.

$doc = new DOMDocument();
$doc->loadHTML($h); // assume HTML in $h

$xpath = new DOMXPath($doc);
$imgs = $xpath->query("//img[@class = 'replaceMe']");

foreach ($imgs as $img) {

    $imgfile = pathinfo($img->getAttribute("src"),PATHINFO_FILENAME);
    if (array_key_exists($imgfile, $myArray)) { 

        $replacement = $doc->createTextNode($myArray[$imgfile]);
        $img->parentNode->replaceChild($replacement, $img); 
    }
}

echo "<pre>" . htmlentities($doc->saveHTML()) . "</pre>";

see it working: http://codepad.viper-7.com/11XZt7