2017-07-03 20 views
2

这个问题的目的是作为参考来回答一个特别常见的问题,这可能会采取不同的形式:参考 - 如何在SimpleXML中处理命名空间(带有冒号的标签和属性)?

  • 我有一个包含多个名称空间的XML文档;我如何使用SimpleXML解析它?
  • 我的XML在标签名称中有一个冒号(“:”),如何使用SimpleXML访问它?
  • 如何访问我的XML文件中的属性时,他们的名称中有冒号?

如果您的问题已被重复关闭,可能与这些示例不同,但此页面应告诉您需要了解的内容。

下面是一个说明性示例:

$xml = ' 
    <?xml version="1.0" encoding="utf-8"?> 
    <document xmlns="http://example.com" xmlns:ns2="https://namespaces.example.org/two" xmlns:seq="urn:example:sequences"> 
     <list type="short"> 
      <ns2:item seq:position="1">A thing</ns2:item> 
      <ns2:item seq:position="2">Another thing</ns2:item> 
     </list> 
    </document> 
'; 
$sx = simplexml_load_string($xml); 

此代码将不起作用;为什么不?

foreach ($sx->list->ns2:item as $item) { 
    echo 'Position: ' . $item['seq:position'] . "\n"; 
    echo 'Item: ' . (string)$item . "\n"; 
} 

的第一个问题是,->ns2:item是无效的语法;但它改变这种无法正常工作或

foreach ($sx->list->{'ns2:item'} as $item) { ... } 

为什么不和你应该怎么使用呢?

+0

相关元讨论:https://meta.stackoverflow.com/questions/351420/canonical-question-for-using-php-simplexml-with-namespaces – IMSoP

回答

4

什么是XML名称空间?

标记或属性名称中的冒号(:)表示元素或属性位于的XML文件夹中。命名空间是在一个文档中结合不同XML格式/标准的方式,并且追踪哪些名称来自哪种格式。冒号,和之前的部分,是不是真正的标记/属性名称的一部分,他们只是表示这是其中的命名空间。

XML命名空间有命名空间标识,这是由URI标识(一个URL或URN)。 URI并不指向任何东西,只是某人“拥有”命名空间的一种方式。例如,SOAP标准使用命名空间http://www.w3.org/2003/05/soap-envelope,并且OpenDocument文件使用(其他)urn:oasis:names:tc:opendocument:xmlns:meta:1.0。该问题中的示例使用名称空间http://example.comhttps://namespaces.example.org/two

在文档或文档的某个部分中,名称空间被赋予一个本地前缀,这是您在冒号前看到的部分。例如,在不同的文档中,SOAP名称空间可能会被赋予本​​地前缀soap:,SOAP:,SOAP-ENV:,env:或仅为ns1:。这些名称使用特殊的xmlns属性链接回名称空间的标识符,例如, xmlns:soap="http://www.w3.org/2003/05/soap-envelope"。在特定文档中选择前缀是完全任意的,并且每次在不改变含义的情况下都可以改变它。

最后,在每个文档或文档的部分中有一个默认命名空间,这是用于没有前缀的元素的命名空间。它由不具有:xmlns属性定义,例如, xmlns="http://www.w3.org/2003/05/soap-envelope"。在上面的示例中,<list>位于默认名称空间中,该空间定义为http://example.com

有点特别,未加前缀的属性从来不在默认名称空间中,而是在标准没有明确定义的“void namespace”中。请参阅:XML Namespaces and Unprefixed Attributes

如何访问SimpleXML中的名称空间?

SimpleXML提供了一个使用命名空间主要有两种方法:

  • The ->children() method允许您访问子元素在一个特定的命名空间。它可以有效地切换对象以查看该名称空间,直到再次调用它返回或返回到另一个名称空间。
  • The ->attributes() method以类似的方式工作,但允许您在特定的命名空间中访问属性

这两种方法都将命名空间标识符作为它们的第一个参数。由于这些标识符相当长,因此定义常量或变量来表示您正在使用的命名空间会很有用,因此您无需在任何地方复制和粘贴完整的URI。

举例来说,上面的例子可能变成:

define('XMLNS_EG2', 'https://namespaces.example.org/two'); 
define('XMLNS_SEQ', 'urn:example:sequences'); 
foreach ($sx->list->children(XMLNS_EG2)->item as $item) { 
    echo 'Position: ' . $item->attributes(XMLNS_SEQ)->position . "\n"; 
    echo 'Item: ' . (string)$item . "\n"; 
} 

作为短手,你也可以通过这些方法的命名空间的本地别名,通过给第二个参数true。请记住,此前缀可能会随时更改,例如,生成器可能会分配前缀ns1ns2等,并且如果代码稍有更改,则可以按不同的顺序分配它们。使用这种速记,代码将变为:

foreach ($sx->list->children('ns2', true)->item as $item) { 
    echo 'Position: ' . $item->attributes('seq', true)->position . "\n"; 
    echo 'Item: ' . (string)$item . "\n"; 
} 

(在PHP 5.2中添加了该短手,您可以使用使用$sx->getNamespaces更啰嗦版本,以获得的列表,请参阅真的老例前缀 - 标识符对)。