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

时间:2019-04-11 21:29:35

标签: php xml simplexml

我正在尝试访问带有名称空间声明的节点中没有名称空间声明的节点列表。我的XML文件有一个主节点,该节点的命名空间为ehd,带有两个子节点头,主体位于同一命名空间内。但是,主体节点内的所有子节点都没有进一步的名称空间声明。我正在努力使用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进行调试

2 个答案:

答案 0 :(得分:3)

就个人而言,一旦您克服了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

答案 1 :(得分:3)

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

但是,本文档中没有前缀的元素没有 namespace -它们位于默认命名空间中,在这种情况下为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);
}