这个问题旨在作为回答一个特别常见问题的参考,这个问题可能有不同的形式:
如果您的问题已与此相关,则可能与这些示例不同,但此页面应告诉您需要了解的内容。
以下是一个说明性示例:
$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 :(得分:8)
标记或属性名称中的冒号(:
)表示该元素或属性位于 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.com
和https://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对象上使用print_r
,var_dump
或类似的“转储结构”函数,则不会显示某些内容。 它仍然存在,可以按照以下说明进行访问。
SimpleXML提供了两种使用命名空间的主要方法:
->children()
method允许您访问特定命名空间中的子元素。它有效地切换您的对象以查看该命名空间,直到您再次调用它来切换回或另一个命名空间。->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
来传递命名空间的本地别名方法。请记住,此前缀可能随时更改,例如,生成器可能会分配前缀ns1
,ns2
等,如果代码稍有变化,则以不同的顺序分配它们。使用这个简写,代码将成为:
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
的更长篇版本的旧版本来获取前缀标识符对的列表。这是两者中最差的世界,因为你仍然在硬编码前缀而不是标识符。)