我需要将XML文档从外部源加载到PHP中。XML未声明其编码,并且包含非法字符,如&。如果尝试直接在浏览器中加载XML文档,则在用PHP加载文件时也会收到诸如“在文本内容中发现无效字符”之类的错误消息,并且还会收到很多警告,例如:xmlParseEntityRef: no name in Entity和Input is not proper UTF-8, indicate encoding ! Bytes: 0x9C 0x31 0x21 0x3C。
&
xmlParseEntityRef: no name in Entity
Input is not proper UTF-8, indicate encoding ! Bytes: 0x9C 0x31 0x21 0x3C
显然,XML格式不正确,并且包含应转换为XML实体的非法字符。
这是因为XML提要由许多其他用户提供的数据组成,并且很明显,在我获得它之前,尚未对其进行验证或重新格式化。
我已经与XML feed的供应商进行了交谈,他们说他们正试图让内容提供商对其进行分类,但这似乎很愚蠢,因为他们应该首先验证输入。
我基本上需要修复XML,以纠正任何编码错误并将任何非法字符转换为XML实体,以便在使用PHP的DOMDocument函数时XML加载问题。
我的代码当前如下所示:
$feedURL = '3704017_14022010_050004.xml'; $dom = new DOMDocument(); $dom->load($feedURL);
显示编码问题的XML文件示例(单击下载):feed.xml
包含未转换为XML实体的字符的示例XML:
<?xml version="1.0"?> <feed> <RECORD> <ID>117387</ID> <ADVERTISERNAME>Test</ADVERTISERNAME> <AID>10544740</AID> <NAME>This & This</NAME> <DESCRIPTION>For one day only this is > than this.</DESCRIPTION> </RECORD> </feed>
尝试使用Tidy库,该库可用于清除不良的HTML和XML http://php.net/manual/zh/book.tidy.php
一个纯PHP解决方案,用于修复如下所示的一些XML:
<?xml version="1.0"?> <feed> <RECORD> <ID>117387</ID> <ADVERTISERNAME>Test < texter</ADVERTISERNAME> <AID>10544740</AID> <NAME>This & This</NAME> <DESCRIPTION>For one day only this is > than this.</DESCRIPTION> </RECORD> </feed>
将是这样的:
function cleanupXML($xml) { $xmlOut = ''; $inTag = false; $xmlLen = strlen($xml); for($i=0; $i < $xmlLen; ++$i) { $char = $xml[$i]; // $nextChar = $xml[$i+1]; switch ($char) { case '<': if (!$inTag) { // Seek forward for the next tag boundry for($j = $i+1; $j < $xmlLen; ++$j) { $nextChar = $xml[$j]; switch($nextChar) { case '<': // Means a < in text $char = htmlentities($char); break 2; case '>': // Means we are in a tag $inTag = true; break 2; } } } else { $char = htmlentities($char); } break; case '>': if (!$inTag) { // No need to seek ahead here $char = htmlentities($char); } else { $inTag = false; } break; default: if (!$inTag) { $char = htmlentities($char); } break; } $xmlOut .= $char; } return $xmlOut; }
这是一个简单的状态机,它指示我们是否在标记中,如果没有,则使用htmlentities编码文本。
值得注意的是,这将占用大文件的内存,因此您可能需要将其重写为流插件或预处理器。