【问题标题】:Why is SimpleXMLElement not able to find contents of XML file?为什么 SimpleXMLElement 无法找到 XML 文件的内容?
【发布时间】:2018-05-27 16:15:22
【问题描述】:

我需要使用 php 解析从第三方收到的 xml 文档。我无法要求文档的维护者修复其结构。当我使用simplexml_load_file 解析文档时,XML 文档为空。

这是我所看到的一个精简示例。

我的文件.xml:

<?xml version="1.0" encoding="utf-8"?>
<DataSet>
  <diffgr:diffgram xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
    aaa
  </diffgr:diffgram>
</DataSet>

我这样处理它(从命令行):

php > $xml = simplexml_load_file('my-file.xml');
php > print_r($xml);
SimpleXMLElement Object
(
)

我期待通过print_r显示xml结构。

确实,当我删除命名空间声明时,一切似乎都正常了(尽管会出现一些预期的 XML 解析警告):

我的文件-nonamespace.xml:

<?xml version="1.0" encoding="utf-8"?>
<DataSet>
  <diffgr:diffgram>
    aaa
  </diffgr:diffgram>
</DataSet>

在命令行上以相同的方式处理它(删除警告):

php > $xml = simplexml_load_file('my-file-nonamespace.xml');

// a bunch of xml parse warnings
php > print_r($xml);
SimpleXMLElement Object
(
    [diffgr:diffgram] =>
    aaa

)

因此,问题与无效的命名空间声明有关。我可能可以在文件上使用正则表达式在解析之前删除命名空间声明,但这不是我想要的方向。

在 PHP 中正确解析第一个文档的最佳方法是什么?

【问题讨论】:

  • 在 SimpleXMLElement 上使用 print_r 通常不会提供您需要的所有信息。
  • 我没有在我的实际代码中使用print_r。我只是用它来说明第一个文件似乎没有孩子,而第二个文件有。当我在第一个文件上调用 var_dump($xml-&gt;children()); 时,我得到 0 个元素。在第二个文件中,我得到 1 个元素。所以,很明显,body 没有被解析。

标签: php xml xml-namespaces


【解决方案1】:

问题不在于未加载数据,而在于子元素位于不同的命名空间中。

$xml = simplexml_load_file('my-file.xml');
var_dump($xml->children("diffgr", true));

这会从当前元素的特定命名空间中选择子元素。

请注意,您应该使用 URI,因为前缀可能会发生变化,但这只是为了表明数据存在。

编辑: 如果 XML 有问题,那么第一阶段是忽略错误,然后检查加载的内容...

libxml_use_internal_errors(true);
$xml = simplexml_load_file('my-file.xml');
echo $xml->asXML();

这将使您了解结果是什么状态,即使它已加载。一个简单的例子是......

libxml_use_internal_errors(true);
$xml = simplexml_load_file('my-file.xml');
echo $xml->asXML();
var_dump($xml->children());

与..

<?xml version="1.0" encoding="utf-8"?>
<DataSet>
  <diffgr:diffgram>
    aaa
  </diffgr:diffgram>
</DataSet>

注意命名空间是如何存在的,但命名空间没有被声明。输出是...

<?xml version="1.0" encoding="utf-8"?>
<DataSet>
  <diffgr:diffgram>
    aaa
  </diffgr:diffgram>
</DataSet>
/home/nigel/workspace2/Test/t1.php:22:
class SimpleXMLElement#2 (1) {
  public $diffgr:diffgram =>
  string(11) "
    aaa
  "
}

这无需使用命名空间即可输出子级。

【讨论】:

  • 谢谢。这适用于我上面的玩具示例,但实际的 xml 文本引用了几个在声明中不存在和/或格式错误的命名空间。有什么方法可以解析 xml,同时忽略命名空间?
  • 在不知道错误是什么的情况下,可能会发生各种各样的事情。我会在答案中添加一些内容。
  • 谢谢,但我知道如果我删除命名空间 xmlns:diffgr,我可以让它工作。您的示例删除了命名空间引用,但我不能这样做(不使用正则表达式进行一些丑陋和危险的准备)。我要做的是保留 xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1" 并且仍然引用文档子项而不使用显式命名空间。
  • 该示例更多地说明了仍然可以加载损坏的 XML。至于不使用命名空间,我看不出问题出在哪里。如果您有带有命名空间的特定格式,请使用它。
  • 所以,我认为您的意思是,没有明确指定命名空间的情况下,没有直接的方法可以访问 SimpleXmlElement 实例的所有子节点。我的目标是避免在遍历节点时指定命名空间,因为这些与我的任务无关。但是,我认为这是不可能的。经过您的解释,我对 API 的理解要好得多。您的解释是有道理的,但我认为 API 本身并不直观,文档也很混乱。
猜你喜欢
  • 2011-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多