Узлы доступа SimpleXML с пространством имен и подузлами без пространства имен - PullRequest
1 голос
/ 12 апреля 2019

Я пытаюсь получить доступ к списку узлов без объявления пространства имен внутри узлов с объявлением пространства имен.В моем 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 ]

2 голосов
/ 12 апреля 2019

Аргументом ->children() всегда является идентификатор пространства имен или локальный префикс, а не имя тега.Если бы эти элементы находились в «пространстве имен», вы бы получили к ним доступ с помощью ->children('').

Однако элементы без префикса в этом документе не имеют пространства имен - они находятся в пространстве имен по умолчанию, в данном случае urn:ehd/go/001 (как определено xmlns="urn:ehd/go/001").

Если вы используете полные идентификаторы пространства имен, а не префиксы (которые также менее вероятно сломаютсяесли фид изменяется), вы сможете легко получить к ним доступ:

$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, но не 't зависит от префиксов, с которыми генерируется 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 голосов
/ 12 апреля 2019

Лично я нахожу DomDocument гораздо более интуитивно понятным для работы - как только вы преодолеете барьер синтаксиса XPath . Независимо от того, каким инструментом вы пользуетесь, пространства имен все усложнят!

$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
...