我正在使用SimpleXML加载一些xml文件(我没有写/提供这些文件并且无法真正改变格式)。
偶尔(例如,每50个左右有一个或两个文件),它们不会逃避任何特殊字符(大多数是&amp ;,但有时也会出现其他随机无效的字符)。这创建并发布,因为带有php的SimpleXML失败了,我真的不知道处理解析无效XML的任何好方法。
我的第一个想法是将XML预处理为一个字符串并将所有字段放在CDATA中以便它可以工作,但是由于一些不正当的原因,我需要处理的XML将所有数据放在属性字段中。因此我不能使用CDATA的想法。 XML的一个例子是:
<Author v="By Someone & Someone" />
在使用SimpleXML加载之前,最好的方法是处理这个以替换XML中的所有无效字符?
答案 0 :(得分:7)
您需要的是使用libxml的内部错误来定位无效字符并相应地转义它们。这是我如何写它的模型。请查看libxml_get_errors()
的错误信息结果。
function load_invalid_xml($xml)
{
$use_internal_errors = libxml_use_internal_errors(true);
libxml_clear_errors(true);
$sxe = simplexml_load_string($xml);
if ($sxe)
{
return $sxe;
}
$fixed_xml = '';
$last_pos = 0;
foreach (libxml_get_errors() as $error)
{
// $pos is the position of the faulty character,
// you have to compute it yourself
$pos = compute_position($error->line, $error->column);
$fixed_xml .= substr($xml, $last_pos, $pos - $last_pos) . htmlspecialchars($xml[$pos]);
$last_pos = $pos + 1;
}
$fixed_xml .= substr($xml, $last_pos);
libxml_use_internal_errors($use_internal_errors);
return simplexml_load_string($fixed_xml);
}
答案 1 :(得分:2)
我认为用于创建compute_position函数的workaroung将在处理之前使xml字符串变平。 重写Josh发布的代码:
function load_invalid_xml($xml)
{
$use_internal_errors = libxml_use_internal_errors(true);
libxml_clear_errors(true);
$sxe = simplexml_load_string($xml);
if ($sxe)
{
return $sxe;
}
$fixed_xml = '';
$last_pos = 0;
// make string flat
$xml = str_replace(array("\r\n", "\r", "\n"), "", $xml);
// get file encoding
$encoding = mb_detect_encoding($xml);
foreach (libxml_get_errors() as $error)
{
$pos = $error->column;
$invalid_char = mb_substr($xml, $pos, 1, $encoding);
$fixed_xml .= substr($xml, $last_pos, $pos - $last_pos) . htmlspecialchars($invalid_char);
$last_pos = $pos + 1;
}
$fixed_xml .= substr($xml, $last_pos);
libxml_use_internal_errors($use_internal_errors);
return simplexml_load_string($fixed_xml);
}
我添加了编码内容,因为我遇到了简单的数组[索引]从字符串中获取字符的问题。
这一切都应该有用,但是,不知道为什么,我已经看到$ error-&gt;列给了我一个不同的数字。尝试通过简单地在xml中添加一些无效字符来调试它,并检查它将返回什么值,但没有运气。 希望有人能告诉我这种方法有什么问题。