DOMDocument问题:转义属性并从javascript中删除标记

时间:2013-09-12 20:44:28

标签: html dom escaping domdocument

我不是DOMDocument的粉丝,因为我相信它对现实世界的使用并不是很好。然而在当前项目中,我需要将页面中的所有文本(我无法访问源代码)替换为其他字符串(某种翻译);所以我需要使用它。

我尝试使用DOMDocument执行此操作,但未收到预期的结果。这是我使用的代码:

function Translate_DoHTML($body, $replaceArray){
    if ($replaceArray && is_array($replaceArray) && count($replaceArray) > 0){
        $body2 = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8");
        $doc = new DOMDocument();
        $doc->resolveExternals = false;
        $doc->substituteEntities = false;
        $doc->strictErrorChecking = false;
        if (@$doc->loadHTML($body2)){
            Translate_DoHTML_Process($doc, $replaceArray);
            $body = $doc->saveHTML();
        }
    }
    return $body;
}

function Translate_DoHTML_Process($node, $replaceRules){
    if($node->hasChildNodes()) {
        $nodes = array();
        foreach ($node->childNodes as $childNode)
            $nodes[] = $childNode;
        foreach ($nodes as $childNode)
            if ($childNode instanceof DOMText) {
                if (trim($childNode->wholeText)){
                    $text = str_ireplace(array_keys($replaceRules), array_values($replaceRules), $childNode->wholeText);
                    $node->replaceChild(new DOMText($text),$childNode);
                }
            }else
                Translate_DoHTML_Process($childNode, $replaceRules);
    }
}

以下是问题:

  • 转义属性:文件中存在转义的数据-X属性。这不是一个主要问题,但如果我可以禁用此行为,那就太棒了。

在DOM之前:

data-link-content="         <a class=&quot;submenuitem&quot; href=&quot

在DOM之后:

data-link-content='         &lt;a class="submenuitem" href="
  • 在javascript中删除结束标记: 这实际上是我的主要问题。我不知道世界上DOMDocument可能有什么理由需要删除这些标记。但确实如此。正如您在下面的示例中可以清楚地看到的,它删除了java脚本字符串中的结束标记。它还删除了脚本的最后一部分。似乎DOMDocument解析了java脚本。也许是因为没有CDATA标签?但无论如何它是HTML,我们不需要HTML格式的CDDATA。我认为CDATA适用于xHTML。另外我无法在这里添加CDDATA。那么我可以要求它不解析脚本标签吗?

在DOM之前:

<script type="text/javascript"> document.write('<video src="http://x.webm"><p>You will need to <a href="http://www.adobe.com/go/getflashplayer" target="_blank">Install</a> the latest Flash plugin to view this page properly.</p></video>');  </script>

在DOM之后:

<script type="text/javascript"> document.write('<video src="http://x.webm"><p>You will need to <a href="http://www.adobe.com/go/getflashplayer" target="_blank">Install the latest Flash plugin to view this page properly.</script>

如果我无法阻止这些事情,有什么办法可以将此代码移植到SimpleHTMLDOM中吗?

非常感谢你。

2 个答案:

答案 0 :(得分:0)

试试这个,并替换行内容;

$body2 = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8");

to;

$body2 = convertor($body);

并插入代码中;

function convertor($ToConvert)
    {
        $FromConvert = html_entity_decode($ToConvert,ENT_QUOTES,'ISO-8859-1');
        $Convert = mb_convert_encoding($FromConvert, "ISO-8859-1", "UTF-8");
        return ltrim($Convert); 
    }

但是在上下文中使用正确的编码。

度过愉快的一天。

答案 1 :(得分:0)

根据我的搜索,第二个问题的原因实际上是“Alex”在这个问题中告诉我们的内容:DOM parser that allows HTML5-style </ in <script> tag

但根据他们的研究,没有好的解析器能够理解今天的HTML。此外,html5lib的最后一次更新是在2年前,根据我的测试,它无法在真实世界的情况下工作。

所以我只有一种方法可以解决第二个问题。正则表达式。这是我使用的代码:

function Translate_DoHTML_GetScripts($body){
    $res = array();
    if (preg_match_all('/<script\b[^>]*>([\s\S]*?)<\/script>/m', $body, $matches) && is_array($matches) && isset($matches[0])){
        foreach ($matches[0] as $key => $match)
            $res["<!-- __SCRIPTBUGFIXER_PLACEHOLDER".$key."__ -->"] = $match;
        $body = str_ireplace(array_values($res), array_keys($res), $body);
    }
    return array('Body' => $body, 'Scripts' => $res);
}

function Translate_DoHTML_SetScripts($body, $scripts){
    return str_ireplace(array_keys($scripts), array_values($scripts), $body);
}

使用上面两个函数,我将从HTML中删除任何脚本,以便我可以使用DomDocument来完成我的工作。然后在最后,我会将它们准确地添加回去。

但我不确定正则表达式是否足够快。

不要告诉我不要使用RegEx for HTML。我知道HTML不是常用语言等等;但如果你自己解决了这个问题,你会建议采用相同的方法。