使用 SimpleXML 使用命名空间解析 XML [重复]

Posted

技术标签:

【中文标题】使用 SimpleXML 使用命名空间解析 XML [重复]【英文标题】:Parse XML with Namespace using SimpleXML [duplicate] 【发布时间】:2010-10-10 09:42:12 【问题描述】:

我有这个作为 xml:

<root xmlns:event="http://www.webex.com/schemas/2002/06/service/event">
    <event:event>
        <event:sessionKey></event:sessionKey>
        <event:sessionName>Learn QB in Minutes</event:sessionName>
        <event:sessionType>9</event:sessionType>
        <event:hostWebExID></event:hostWebExID>
        <event:startDate>02/12/2009</event:startDate>
        <event:endDate>02/12/2009</event:endDate>
        <event:timeZoneID>11</event:timeZoneID>
        <event:duration>30</event:duration>
        <event:description></event:description>
        <event:status>NOT_INPROGRESS</event:status>
        <event:panelists></event:panelists>
        <event:listStatus>PUBLIC</event:listStatus>
    </event:event>
    ...
</root>

如何循环遍历所有 event:event 节点并显示,例如,所有 event:SessionKey 的?

这不起作用:

$xml = new SimpleXMLElement($r);
$xml->registerXPathNamespace('e', 'http://www.webex.com/schemas/2002/06/service/event');

foreach($xml->xpath('//e:event') as $event) 
 var_export($event->xpath('//e:sessionKey'));

【问题讨论】:

这可能有助于lornajane.net/posts/2010/… does not work 是而且从来都不是正确的错误描述。 php 给你以下错误:“警告:SimpleXMLElement::xpath(): 未定义的命名空间前缀”。如果你开发软件,你应该听从 PHP 的警告。另请参阅:How to get useful error messages in PHP? 另见Reference - how do I handle namespaces (tags and attributes with colon in) in SimpleXML? 【参考方案1】:

它确实可以在没有 registerXPathNamespace 和 xpath 查询中的完整命名空间前缀的情况下工作:

$xml = new SimpleXMLElement($r);

foreach($xml->xpath('//event:event') as $event) 
 var_export($event->xpath('event:sessionKey'));

【讨论】:

是也不是,实际上我认为这是一个错误。 PHP 自动注册当前上下文的命名空间。这甚至会覆盖您自己注册的命名空间。您的来源基于您加载的文档中使用的前缀。您无法控制的外部来源。可选的、不明确的并且可以随时更改的前缀。命名空间已定义、唯一且稳定 - 前缀/别名不是。【参考方案2】:

您必须为您使用的每个 simpleXMLElement 对象注册命名空间。

$xml = new SimpleXMLElement($r);
$xml->registerXPathNamespace('e', 'http://www.webex.com/schemas/2002/06/service/event');

foreach($xml->xpath('//e:event') as $event) 
    $event->registerXPathNamespace('e', 'http://www.webex.com/schemas/2002/06/service/event');
    var_export($event->xpath('//e:sessionKey'));

命名空间也应该在 xml 文件中的某处声明。

<event:event xmlns:event="http://www.webex.com/schemas/2002/06/service/event">
...

所描述的方法 ax 也有效。如果您知道 xml 文件将始终使用相同的前缀,则可以跳过 registerXPathNamespace。

【讨论】:

【参考方案3】:

这里的替代方案对我有用。

$xml = simplexml_load_string($r);
$ns = $xml->getNamespaces(true);

foreach ($xml->children($ns['event'])->event as $skey) 
    $sessionKey = $skey->children($ns['event'])->sessionKey;
    echo $sessionKey;

【讨论】:

诀窍是使用children() 至少带有它的第一个参数。如果您事先知道文档结构,您甚至可以手动输入命名空间名称(或其 URI)来替代getNamespaces() 为了更简单的打字技巧是投射到对象,即$ns = (object) $xml-&gt;getNamespaces(true);然后你可以像$sessionKey = $skey-&gt;children($ns-&gt;event)-&gt;sessionKey;一样使用它【参考方案4】:

使用 simplexml 做了很多工作,我就是这样做的。

如果您已经有一个元素并且只想获取它的不同命名空间的子元素,那么魔术技巧,比如这样的结构:

<entry>
<title type="text">My test entry</title>
<gd:when startTime="2017-02-26T02:00:00Z" endTime="2017-02-26T03:00:00Z"/>
<gc:notes type="string">A type</gc:notes>
</entry>

是将TRUE作为第二个参数发送给children函数:

  $title = (string) $entry->title;
  $gd = $entry->children('gd', TRUE);
  $attrs = $gd->when->attributes();
  $startTime = (string) $attrs->startTime;
  $gc = $entry->children('gc', TRUE);
  $notes = (string) $gc->notes();

【讨论】:

【参考方案5】:

另一种方法是使用SimpleXML 进行解析,使用DOMDocument 进行操作/访问,这完全绕过了命名空间问题:

$xml = new SimpleXMLElement($r);
$xml = dom_import_simplexml($xml);
$nodelist= $xml->getElementsByTagName('event');  
for($i = 0; $i < $nodelist->length; $i++) 
    $sessions = $nodelist->item($i)->getElementsByTagName('sessionKey');
    echo $sessions->item(0)->nodeValue;

【讨论】:

【参考方案6】:

使用registerXPathNamespace 然后调用xpath 实际上对我不起作用。 我不得不采用这篇很棒的帖子中提供的解决方案:http://blog.preinheimer.com/index.php?/archives/172-SimpleXML,-Namespaces-Hair-loss.html

所以在你的情况下,这个:

echo $xml->children('http://www.webex.com/schemas/2002/06/service/event')->sessionName;

将输出:

在几分钟内了解 QB

【讨论】:

以上是关于使用 SimpleXML 使用命名空间解析 XML [重复]的主要内容,如果未能解决你的问题,请参考以下文章

使用 php SimpleXML 解析 XML 命名空间

SimpleXML 中的 XPath 用于默认命名空间,无需前缀

如何在命名空间环境中访问 SimpleXML 节点?

简单的xml添加命名空间的孩子

PHP SimpleXML->addChild - 不需要的空命名空间属性

『XML』XML/XSD命名空间解析