如何在PHP中清理/验证XML文件? PCDATA错误

时间:2018-03-16 17:15:26

标签: php xml utf-8 simplexml domdocument

我收到的XML文件我无法控制,我需要从中提取数据。这是我的代码:

public function importXML($filePath)
{
    $dom = new \DOMDocument();
    $dom->load($filePath);

    $xml = simplexml_import_dom($dom);
    foreach ($xml->PLU as $item) {
        $name = $item->NAME;

我在某处读到DOMDocument()对xml的一部分进行了清理,因此最好先将文件加载到那里,然后通过simplexml_import_dom()导入它。截至目前,这段代码有70%的时间可以正常运行,而且我成功地按照自己的意愿行事,但另外30%的时间我收到此错误:

[ExceptionError] DOMDocument :: load():PCDATA invalid char / / path / to / file.xml中的值31,第2行

我已经围绕这个问题进行了一些挖掘,我找到了一个可能的解决方案,但就我而言,它并没有:

第一个选项:

function utf8_for_xml($string)
{
    return preg_replace ('/[^\x{0009}\x{000a}\x{000d}\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}]+/u', ' ', $string);
}

但是我尝试在Simplexml_import_dom()之前将我的$ dom加载文件放入其中,但是它给出了同样的错误。

第二个选项:

function stripInvalidXml($value)
{
    $ret = "";
    $current;
    if (empty($value)) 
    {
        return $ret;
    }

    $length = strlen($value);
    for ($i=0; $i < $length; $i++)
    {
        $current = ord($value{$i});
        if (($current == 0x9) ||
            ($current == 0xA) ||
            ($current == 0xD) ||
            (($current >= 0x20) && ($current <= 0xD7FF)) ||
            (($current >= 0xE000) && ($current <= 0xFFFD)) ||
            (($current >= 0x10000) && ($current <= 0x10FFFF)))
        {
            $ret .= chr($current);
        }
        else
        {
            $ret .= " ";
        }
    }
    return $ret;
}

我也没有运气,因为错误继续发生。 XML文件编码是&#34; WINDOWS-1251&#34;一些文件使用Cyrilic,如果这可以帮助。

编码中的问题或者是关于XML文件有效性的问题(打开和关闭标记等)?

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

感谢@NigelRen,我做了以下工作并且效果很好:

    private function stripInvalidXml($value)
{
    $ret = "";
    $current;
    if (empty($value)) 
    {
        return $ret;
    }

    $length = strlen($value);
    for ($i=0; $i < $length; $i++)
    {
        $current = ord($value{$i});
        if (($current == 0x9) ||
            ($current == 0xA) ||
            ($current == 0xD) ||
            (($current >= 0x20) && ($current <= 0xD7FF)) ||
            (($current >= 0xE000) && ($current <= 0xFFFD)) ||
            (($current >= 0x10000) && ($current <= 0x10FFFF)))
        {
            $ret .= chr($current);
        }
        else
        {
            $ret .= " ";
        }
    }
    return $ret;
}

我使用第二种方法进行验证我发现加上用file_get_contents打开xml然后修改它:

public function importXML($filePath)
{
    $content = file_get_contents($filePath);
    $modified = $this->stripInvalidXml($content);

    $dom = new \DOMDocument();
    $dom->loadXML($modified);

    $xml = simplexml_import_dom($dom);

现在$ xml是有效的,可以在你找到合适的时候进行处理。