You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP DOMDocument替换DOM文本仅生效于首个标签问题求助

问题:PHP DOMDocument仅替换每个section下第一个标签内容的问题

我使用PHP DOMDocument遍历一段HTML字符串,希望将每个包含文本值的标签内容替换为自定义Vue插值字符串,但出现问题:仅每个section的第一个标签内容被替换,需要实现所有section内的标签内容都被替换。

原始HTML字符串

$htmlString = "<section>
        <p>text</p>
        <p>text</p>
    </section>
    <section>
        <h2>text</h2>
            <p>text</p>
            <p>text</p>
    </section>"

我的实现代码

$dom = new \DOMDocument();
libxml_use_internal_errors(true);

$htmlString = mb_convert_encoding($htmlString, 'HTML-ENTITIES', 'UTF-8');
$dom->loadHTML($htmlString);

$count = 0;
$keyPattern = 'ccpaRights';

foreach ($dom->getElementsByTagName('section') as $section)
{
    // loop through each child of <section>
    foreach ($section->childNodes as $childNode)
    { 
         $nodeValue = trim($childNode->nodeValue); 

        if ($nodeValue === '')
        {
            continue; 
        }

        $count = $count + 1;
        $key = (string) $keyPattern.'Text'.$count;
        
        $vueInterpolation = ' {{ $t('.'"'.$key.'"'.' }} ';

        $newNode = $dom->createElement($childNode->nodeName, $vueInterpolation );

        $childNode->parentNode->replaceChild($newNode, $childNode);
    }
}

$dom->saveHTML($dom);
$dom->save(public_path('/temp/result.html'));

当前错误结果

<section>
    <p> {{ $t("ccpaRightsText1" }} </p>
    <p>text</p>
</section>
<section>
    <h2> {{ $t("ccpaRightsText2" }} </h2>
        <p>text</p>
        <p>text</p>
</section>

期望结果

<section>
        <p> {{ $t("ccpaRightsText1" }} </p>
        <p> {{ $t("ccpaRightsText2" }} </p>
    </section>
    <section>
        <h2> {{ $t("ccpaRightsText3" }} </h2>
            <p> {{ $t("ccpaRightsText4" }} </p>
            <p> {{ $t("ccpaRightsText5" }} </p>
    </section>

问题原因

$section->childNodes返回的是动态DOMNodeList对象,而非静态数组。当替换节点时,列表的内部索引会实时变化,导致遍历过程跳过后续节点——比如第一个节点被替换后,原第二个节点的索引变为第一个,但遍历指针已移动到下一个位置,直接跳过了它。

解决方案

将动态的DOMNodeList转换为静态数组后再遍历,确保遍历过程不受DOM结构修改的影响。同时修复原代码中Vue插值的语法错误:

修改后的核心代码

foreach ($dom->getElementsByTagName('section') as $section)
{
    // 将childNodes转为静态数组,避免动态列表导致的遍历跳过问题
    foreach (iterator_to_array($section->childNodes) as $childNode)
    { 
         $nodeValue = trim($childNode->nodeValue); 

        if ($nodeValue === '')
        {
            continue; 
        }

        $count = $count + 1;
        $key = (string) $keyPattern.'Text'.$count;
        
        $vueInterpolation = ' {{ $t("'.$key.'") }} '; // 修复$t()的闭合括号缺失问题

        $newNode = $dom->createElement($childNode->nodeName, $vueInterpolation );

        $childNode->parentNode->replaceChild($newNode, $childNode);
    }
}

说明

  • iterator_to_array()将动态DOMNodeList转为静态数组,遍历数组时,即使DOM结构变化,数组内的节点引用不会改变,确保所有符合条件的节点都能被处理。
  • 补全了原代码中$t()的闭合括号,避免Vue语法错误。

内容的提问来源于stack exchange,提问作者gabogabans

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 07:32:08