从 API 读取 XML 的数据过早结束

Premature end of data reading an XML from an API

提问人:Sindo 提问时间:6/9/2023 更新时间:6/9/2023 访问量:71

问:

我从一家公司提供的 API 收到 XML。

当我尝试阅读它时,大多数产品进口都很好——除了这个。

<?xml version="1.0" encoding="utf-8"?>
<pfeed lastaccess="31-12-2010 00:00:00">
<p>
    <p_descs lastmodified="1-4-2022 05:28:25">
        <p_desc_std_N lastmodified="31-3-2022 00:17:37">
            <![CDATA[Test product]]>
        </p_desc_std_N>
        <p_desc_ext_N lastmodified="31-3-2022 00:21:31">
            <![CDATA[<h3>Test product</h3><div class="eq items-block with-gutter items-50-50-100" data-minwidth="" data-maxwidth=""><div class="item item-2"><div class="item-stylable">Lorem ipsum</div></div></div><p><strong>Dolor</strong> justo ultricies vehicula<br /></p>]]>
        </p_desc_ext_N>
    </p_descs>
</p>
</pfeed>

这里的问题是每个产品都有一个节点 p - /p。在 CDATA 中还有一个 p - /p,
它会导致该产品的导入失败并返回

simplexml_load_string():实体:第 10 行:解析器错误:标记 p 行 2“”“ 中的数据过早结束

如果我删除段落html标签,它运行平稳。

我正在使用 XmlStringStreamer 解析 XML,因为它是 500+ MB。
然后,通过简单的simplexml_load_string读取每个节点

// $node will be a string like this: "<customer><firstName>Jane</firstName><lastName>Doe</lastName></customer>"

            try {
                $simpleXmlNode = simplexml_load_string( $node );
            } catch (\Exception $e) {
                echo $e->getMessage();
                dd($node);
            }

有没有办法忽略CDATA条目中的html?
通过在线解析器拉取 XML 不会引发错误,因为 XML 是正确的 - 但他们也能够毫无问题地读取 XML,所以我认为这是一个小问题,我正在寻找解决方案。

提前致谢。

我尝试了几种方法,例如用 htmlentitities 替换 CDATA 标签中的所有 html 或完全删除段落标签,但都失败了。

PHP Laravel 简单XML

评论

0赞 Michael Kay 6/9/2023
看起来您正在使用的 XML 解析器只是有问题。

答:

0赞 ThW 6/9/2023 #1

这听起来像是 XmlStringStreamer 部件的问题。也许你需要以不同的方式使用它。

读取大型 XML 文件的“标准”工具是 XMLReader。您可以使用它来迭代节点并将它们扩展到 DOM 中。 DOM 可以导入到 SimpleXML 中。p

$reader = new XMLReader();
$reader->open(getXMLURI());

// bootstrap DOM for expanded nodes
$document = new DOMDocument();
$xpath = new DOMXpath($document);

while ($reader->read() && $reader->localName !== 'p') {
  continue;
}

while ($reader->localName === 'p') {
  // expand to DOM - this will load the current node and all descendants
  $p = $reader->expand($document);
  // use xpath to access values ...
  var_dump($xpath->evaluate('string(p_descs/@lastmodified)', $p));
  // ... or nodes ...
  foreach ($xpath->evaluate('p_descs/*', $p) as $node) {
      var_dump($node->localName, $node->textContent);
  }
  // ... or import to SimpleXML
  $pElement = simplexml_import_dom($p);
  
  // go to following "p" sibling node
  $reader->next('p');
}
$reader->close();

function getXMLUri() {
    $data = <<<'XML'
<?xml version="1.0" encoding="utf-8"?>
<pfeed lastaccess="31-12-2010 00:00:00">
<p>
    <p_descs lastmodified="1-4-2022 05:28:25">
        <p_desc_std_N lastmodified="31-3-2022 00:17:37">
            <![CDATA[Test product]]>
        </p_desc_std_N>
        <p_desc_ext_N lastmodified="31-3-2022 00:21:31">
            <![CDATA[<h3>Test product</h3><div class="eq items-block with-gutter items-50-50-100" data-minwidth="" data-maxwidth=""><div class="item item-2"><div class="item-stylable">Lorem ipsum</div></div></div><p><strong>Dolor</strong> justo ultricies vehicula<br /></p>]]>
        </p_desc_ext_N>
    </p_descs>
</p>
</pfeed>
XML;
return 'data://text/xml;base64,'.base64_encode($data);
}

评论

0赞 Sindo 6/9/2023
这让我走上了正确的道路!谢谢@ThW!