【问题标题】:Fix malformed XML in PHP before processing using DOMDocument functions在使用 DOMDocument 函数处理之前修复 PHP 中格式错误的 XML
【发布时间】:2011-01-16 17:16:51
【问题描述】:

我需要将来自外部源的 XML 文档加载到 PHP 中。 XML 未声明其编码并包含非法字符,例如&。如果我尝试直接在浏览器中加载 XML 文档,我会收到诸如“在文本内容中发现无效字符”之类的错误,在 PHP 中加载文件时也会收到很多警告,例如:xmlParseEntityRef: no name in EntityInput is not proper UTF-8, indicate encoding ! Bytes: 0x9C 0x31 0x21 0x3C

很明显,XML 格式不正确,并且包含应转换为 XML 实体的非法字符。

这是因为 XML 提要由许多其他用户提供的数据组成,显然在我得到它之前它没有经过验证或重新格式化。

我已经与 XML 提要的供应商进行了交谈,他们说他们正试图让内容提供商对其进行整理,但这似乎很愚蠢,因为他们应该首先验证输入。

我基本上需要修复 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>

【问题讨论】:

  • “所有其他满意的客户(?)如何处理数据以及为什么我是唯一一个悲惨的人” - 这是我要问供应商的问题。你能提供一个(确切的)示例文档吗?
  • 我自己也想知道。我与他们交谈过,他们告诉我他们遇到了数据质量问题,并告诉内容提供商对其进行整理。我假设其他客户在尝试处理 XML 提要之前已经找到了修复 XML 提要的方法。因此我的问题。
  • @VolkerK 我已将整个 XML 文档的一个子集作为完整的 XML 上传,超过 42,000 行。

标签: php xml domdocument


【解决方案1】:

要解决此问题,请在加载 XML 文档之前将 DomDocument recover property 设置为 TRUE

$dom-&gt;recover = TRUE;

试试这个代码:

$feedURL = '3704017_14022010_050004.xml';
$dom = new DOMDocument();
$dom->recover = TRUE;
$dom->load($feedURL);

【讨论】:

  • 适用于“实体中文档末尾的额外内容”警告,请参阅eval.in/26395
【解决方案2】:

尝试使用可用于清理不良 HTML 和 XML 的 Tidy 库 http://php.net/manual/en/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 对文本进行编码。

值得注意的是,这会占用大文件的内存,因此您可能需要将其重写为流插件或预处理器。

【讨论】:

  • 我无法让它在我的 Mac 上与 MAMP 一起使用。这真的很令人沮丧。
  • 有一个类似于 Tidy 的纯 PHP 库,称为 htmLawed [bioinformatics.org/phplabware/internal_utilities/htmLawed]。你可能会有更多的运气。
  • 这看起来很有趣,虽然它似乎更多的是关于修复 XML 错误。我遇到的实际错误与尚未转换为 XML 实体的内容和字符的混合编码有关。
  • 理想情况下,我需要一些 PHP 来修复编码错误。您可以通过单击问题底部的示例链接来查看错误示例。我尝试安装 Tidy,但它无法在我的网络服务器上运行。
  • 问题实际上与您加载 XML 的编码有关,解决方案在这里:stackoverflow.com/questions/1269485/…
【解决方案3】:

如果不能选择整洁的扩展,你可以考虑htmlpurifier

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-04
    • 2011-03-02
    • 2015-06-19
    • 2011-10-10
    • 1970-01-01
    • 2015-04-19
    相关资源
    最近更新 更多