php – 参考 – 如何在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 ) { ... }
为什么不呢,你应该用什么呢?
解决方法:
什么是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.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给了我一个空对象;怎么了?
如果在名称空间为的SimpleXML对象上使用print_r,var_dump或类似的“转储结构”函数,则不会显示某些内容.它仍然存在,可以按如下所述进行访问.
如何在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来传递方法名称空间的本地别名.请记住,此前缀可能随时更改,例如,生成器可能会分配前缀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的更长篇版本的旧例子来获取前缀标识符对的列表.这是两个世界中最糟糕的,因为你仍然在硬编码前缀而不是标识符.)
标签:php,xml-namespaces,simplexml 来源: https://codeday.me/bug/20190911/1803272.html