具有名称空间和没有名称空间的子节点的SimpleXML访问节点

问题描述 投票:1回答:2

我试图在具有名称空间声明的节点内访问没有名称空间声明的节点列表。我的XML文件有一个主节点,命名空间为ehd,在同一名称空间内有两个子节点标头。但是,body节点中的所有子节点都没有进一步的名称空间声明。我正在努力使用SimpleXML访问这些节点。

摘自xml文件:

<?xml version="1.0" encoding="ISO-8859-15"?>
<ehd:ehd ehd_version="1.40" xmlns:ehd="urn:ehd/001" xmlns="urn:ehd/go/001">
    <ehd:header>
    </ehd:header>
    <ehd:body>
        <gnr_liste>
            <gnr V="01100"></gnr>
            <gnr V="01101"></gnr>
            <gnr V="01102"></gnr>
        </gnr_liste>
</ehd:body>
</ehd:ehd>

我的代码如下:

$xml = simplexml_load_file($file) or die("Failed to load");   
    $ehd = $xml->children('ehd', true)->body;
    simplexml_dump($ehd);
    $gnr_liste = $ehd->children('gnr_liste')->children('gnr');
    simplexml_dump($gnr_liste);

输出是:

SimpleXML object (1 item)
[
    Element {
        Namespace: 'urn:ehd/001'
        Namespace Alias: 'ehd'
        Name: 'ehd'
        String Content: ''
        Content in Namespace ehd
            Namespace URI: 'urn:ehd/001'
            Children: 2 - 1 'body', 1 'header'
            Attributes: 0
        Content in Default Namespace
            Children: 0
            Attributes: 1 - 'ehd_version'
    }
]
SimpleXML object (1 item)
[
    Element {
        Namespace: 'urn:ehd/001'
        Namespace Alias: 'ehd'
        Name: 'body'
        String Content: ''
        Content in Default Namespace
            Namespace URI: 'urn:ehd/go/001'
            Children: 1 - 1 'gnr_liste'
            Attributes: 0
    }
]

如何从gnr节点访问所有gnr_liste项目?

注意:我使用simplexml_dump进行调试

php xml simplexml
2个回答
2
投票

->children()的参数始终是名称空间标识符或本地前缀,而不是标记名称。如果这些元素在“无名称空间”中,您可以使用->children('')访问它们。

但是,本文档中没有前缀的元素没有命名空间 - 它们位于默认命名空间中,在本例中为urn:ehd/go/001(由xmlns="urn:ehd/go/001"定义)。

如果您使用完整的命名空间标识符而不是前缀(如果Feed更改,它也不太可能中断),您应该能够轻松访问这些:

$xml = simplexml_load_file($file) or die("Failed to load");   
$ehd = $xml->children('urn:ehd/001')->body;
$gnr_liste = $ehd->children('urn:ehd/go/001')->gnr_liste;
foreach ( $gnr_liste->gnr as $gnr ) {
    simplexml_dump($gnr);
}

您可能希望为命名空间指定自己的名称,这样您就不必使用完整的URI,但不依赖于生成XML的前缀;一种常见的方法是定义常量:

const XMLNS_EHD_MAIN = 'urn:ehd/001';
const XMLNS_EHD_GNR = 'urn:ehd/go/001';

$xml = simplexml_load_file($file) or die("Failed to load");   
$ehd = $xml->children(XMLNS_EHD_MAIN)->body;
$gnr_liste = $ehd->children(XMLNS_EHD_GNR)->gnr_liste;
foreach ( $gnr_liste->gnr as $gnr ) {
    simplexml_dump($gnr);
}

2
投票

就个人而言,我发现DomDocument更直观易用 - 一旦你克服了XPath syntax的障碍。无论你使用什么工具,命名空间都会让一切变得更加困难!

$xml = <<< XML
<?xml version="1.0" encoding="ISO-8859-15"?>
<ehd:ehd ehd_version="1.40" xmlns:ehd="urn:ehd/001" xmlns="urn:ehd/go/001">
    <ehd:header>
    </ehd:header>
    <ehd:body>
        <gnr_liste>
            <gnr V="01100"></gnr>
            <gnr V="01101"></gnr>
            <gnr V="01102"></gnr>
        </gnr_liste>
</ehd:body>
</ehd:ehd>
XML;

$dom = new DomDocument;
$dom->loadXML($xml);
$xp = new DomXPath($dom);
// need to get tricky due to namespaces https://stackoverflow.com/a/16719351/1255289
$nodes = $xp->query("//*[local-name()='gnr']/@V");
foreach ($nodes as $node) {
    printf("%s\n", $node->value);
}

输出:

01100
01101
01102
© www.soinside.com 2019 - 2024. All rights reserved.