编程语言
首页 > 编程语言> > php – 参考 – 如何在SimpleXML中处理名称空间(带冒号的标签和属性)?

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