用HTML特殊字符加载DOMDocument(php)

4
我在使用PHP加载XML文件时遇到问题,需要使用DOMDocument功能中的getElementsByTagName函数。以下是我使用的代码:
```php $dom = new DomDocument('1.0', 'UTF-8'); $dom->resolveExternals = false; $dom->load($_FILES["file"]["tmp_name"]); ```
我遇到的错误信息为:
``` 警告:DOMDocument :: load()[domdocument.load]:实体 'rsquo' 未在/tmp/php1VRb3N中定义,行:4 /www/htdocs/bla/upload.php on line 51 ```
原因是我的XML文件中包含一个未定义的实体“rsquo”。
3个回答

3
您的XML解析器没有错误。这是一个无效(甚至不是格式良好的)文档,您将无法使用任何东西加载它。 rsquo是HTML中预定义的实体,但在XML中不是。在XML文档中,如果您想使用除最基本的内置实体(ampltgtquotapos)之外的任何内容,则必须在由<!DOCTYPE>声明引用的DTD中定义它们。(这是XHTML的做法。)
您需要找出输入来源并修复造成问题的任何因素,因为目前它根本不是XML。请使用字符引用(&#8217;)或UTF-8编码中的纯字面字符
作为最后的手段,如果您真的必须接受此格式不正确的输入,则可以对文件进行恶意字符串替换:
$xml= file_get_contents($_FILES['file']['tmp_name']);
$xml= str_replace('&rsquo;', '&#8217;', $xml);
$dom->loadXML(xml);

如果您需要对所有非XML HTML实体进行此操作,而不仅仅是rsquo,那就有点棘手了。您可以进行正则表达式替换:

function only_html_entity_decode($match) {
    if (in_array($match[1], array('amp', 'lt', 'gt', 'quot', 'apos')))
        return $match[0];
    else
        return html_entity_decode($match[0], ENT_COMPAT, 'UTF-8');
}
$xml= preg_replace_callback('/&(\w+);/', 'only_html_entity_decode', $xml);

这种方法仍然不太好,因为它会破坏像注释、CDATA节和PIs等位置中的任何&\w+;字符序列,而这并不实际意味着实体引用。但考虑到这种有缺陷的输入,这可能是你能做的最好的。

当然,这肯定比在整个文档上调用html_entity_decode要好得多,后者还会搞乱任何XML实体引用,导致在存在现有的&amp;&lt;时文档崩溃。

另一个可疑的hack方式是使用loadHTML()加载文档。


2
为了使用该实体,它必须在DTD中进行定义。否则,它就是无效的XML。如果您没有DTD,应该在使用DOM加载XML之前对实体进行解码:
$dom->load(
    html_entity_decode(
        file_get_contents($_FILES["file"]["tmp_name"]), 
        ENT_COMPAT, 'UTF-8'));

0

在 bobince 的帮助下,我的解决方案如下:

    $xml= file_get_contents($_FILES['file']['tmp_name']);
    $xml= preg_replace('/&(\w+);/', '', $xml);
    $dom = new DomDocument();
    $dom->loadXML($xml);

这也会丢弃所有的XML预定义实体引用,如&amp;&lt;。你真的确定要这样做吗? - bobince
是的,没问题。在我的文件中没有预定义的 XML 实体引用,如 &amp;&lt; - BenRoe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接