PHP/DOM方法来改变不在<;pre>;或者<;代码>;标签,不带JavaScript


PHP / DOM method to change image-paths that are not within <pre> or <code> tags, without JavaScript

任务:

  1. 所有出现的情况都必须替换为常数DEVICE的值,我已经使用其他函数定义了该值BUT不应从包装在<pre><code>标记内的代码中替换。

  2. 此任务需要在不使用任何JavaScript的情况下完成。

样品标记:

<div class="wrapper">
<img src="img/demo/desktop-img/sample1.jpg" width="200" height="200" alt="image">
<img src="img/demo/desktop-img/sample2.jpg" width="200" height="200" alt="image">
<pre>
<img src="img/demo/desktop-img/sample1.jpg" width="200" height="200" alt="image">
<img src="img/demo/desktop-img/sample2.jpg" width="200" height="200" alt="image">
</pre>
<code>
<img src="img/demo/desktop-img/sample1.jpg" width="200" height="200" alt="image">
<img src="img/demo/desktop-img/sample2.jpg" width="200" height="200" alt="image">
</code>
</div>

我尝试了以下操作,但它也替换了<pre><code>标记中的出现,这正是不应该发生的事情。我使用PHP作为我的编程语言。

$content = str_replace('/desktop-img/', '/' . DEVICE . '-img/', $content);

我甚至尝试了以下操作,但没有成功

<?php
function changeImagePaths ($content) { // content here comes as string via some other functon.
    $dom = new DOMDocument;
    $dom->loadHTML($content);
    $nodes = $dom->getElementsByTagName('[self::img][not(ancestor::pre) and not(ancestor::code)]');
    foreach( $nodes as $node ) {
        // What is the correct way to retrive all image-paths
        // that are not wrapped within <pre> or <code> tags and how to use them in the code?
        $node->nodeValue = str_replace('desktop-img', DEVICE, $node->nodeValue);
    }
    $content = $dom->saveHTML();
    return $content;
}
?>

挑战:

我认为使用DOM方法应该是可能的,但我无法找出正确的语法。

我对编程很陌生,因此仍在学习过程中。请温和一点,用代码示例说明你的答案,以便于理解。

我的问题:

  1. DOM方法的正确语法应该是什么
  2. 使用DOM是正确的方法吗
  3. 使用DOM方法会有任何挑战/性能打击吗
  4. 在不使用JavaScript的情况下,还有其他更好的方法吗

这是一个快速的工作,所以看起来可能不太好,但希望你能明白。

在线演示

function walkDOM($node)
{
    if($node->nodeName=="pre" || $node->nodeName=="code")
    {
        return;
    }
    elseif($node->nodeName=="img")
    {
        $node->attributes->getNamedItem("src")->nodeValue=str_replace('desktop-img','mobile-img',$node->attributes->getNamedItem("src")->nodeValue);
    }
    elseif($node->hasChildNodes())
    {
        foreach($node->childNodes as $child)
        {
            walkDOM($child);
        }
    }
}
function changeImagePath($html)
{
    $dom=new DOMDocument;
    $dom->preserveWhiteSpace=true;
    $dom->loadHTML($html);
    $root=$dom->documentElement;
    walkDOM($root);
    $dom->formatOutput=false;
    return $dom->saveHTML($root);
}

这个想法是递归地遍历DOM树,跳过每个<pre><code>,并更改遇到的所有<img>

这是非常直接的,但您可能会注意到,由于您将其视为HTML,DOM会自动添加一些标签来"实现"它,并以一种(IMO)非常奇怪的方式对其进行格式化。

Xpath是您的朋友:

$xpath = new DOMXpath($dom);
foreach($xpath->query('//img[not(ancestor::pre) and not(ancestor::code)]') as $img){
  $img->setAttribute('src', 'foo');
}
$path1='C:/ff/ss.html';
$file=file_get_contents($path1);
$dom = new DOMDocument;
@$dom->loadHTML($file);
$links = $dom->getElementsByTagName('img');
//extract img src path from the html page 
foreach ($links as $link) { 
    $re= $link->getAttribute('src');
    $a[]=$re;
}
$oldpth=explode('/',$path1);
$c=count($oldpth)-1;
$fname=$oldpth[$c];
$pth=array_slice($oldpth,0,$c);
$cpth=implode('/',$pth);
foreach($a as $v) {
    if(is_file ($cpth.'/'.$v)) { 
        $c=explode('/',$v);
        $c[0]="xyz007";
        $f=implode('/',$c);
        $file=str_replace ($v,$f,$file);
    }
}
$path2='D:/mail/newpath/';
$wnew=fopen($path2.$fname,'w+');
fwrite($wnew,$file);