【问题标题】:How to sanitize/validate XML file in PHP? PCDATA error如何在 PHP 中清理/验证 XML 文件? PCDATA 错误
【发布时间】:2018-03-16 17:15:26
【问题描述】:

我正在接收我无法控制的 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 Value 31 in /path/to/file.xml, line 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 文件编码是“WINDOWS-1251”,如果有帮助的话,一些文件使用 Cyrilic。

是编码的问题还是XML文件的有效性(打开和关闭标签等)?

任何帮助将不胜感激。

【问题讨论】:

  • 与其对原始字节进行抨击,为什么不尊重 XML 标头中的编码?
  • @tadman 那将如何实现,有什么例子吗?
  • 你可以四处寻找更健壮的 XML 解析器,应该可以的。
  • 使用所有这些处理代码示例,您将需要加载文件(使用 file_get_contents() 或类似名称)并处理 XML 源。然后使用$dom-&gt;loadXML($modifiedSource); 加载这个修改过的源代码。

标签: php xml utf-8 simplexml domdocument


【解决方案1】:

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

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

    $length = strlen($value);
    for ($i=0; $i < $length; $i++)
    {
        // For >PHP7.3 use ord($value[$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 是有效的,可以根据您的需要进行处理。

【讨论】:

    猜你喜欢
    • 2021-01-30
    • 1970-01-01
    • 1970-01-01
    • 2017-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-20
    • 2016-02-12
    相关资源
    最近更新 更多