Пространства имен и XPath

0

Я изучаю XML и PHP, в основном XPath и другие парсеры.

Здесь будет xml:

<?xml version="1.0" encoding="UTF-8"?>

<root xmlns:foo="http://www.foo.org/" xmlns:bar="http://www.bar.org">
    <actors>
        <actor id="1">Christian Bale</actor>
        <actor id="2">Liam Neeson</actor>
        <actor id="3">Michael Caine</actor>
    </actors>
    <foo:singers>
        <foo:singer id="4">Tom Waits</foo:singer>
        <foo:singer id="5">B.B. King</foo:singer>
        <foo:singer id="6">Ray Charles</foo:singer>
    </foo:singers>
    <items>
        <item id="7">Pizza</item>
        <item id="8">Cheese</item>
        <item id="9">Cane</item>
    </items>
</root>

Вот мой путь и код:

$xml = simplexml_load_file('xpath.xml');

$result = $xml -> xpath('/root/actors');

echo '<pre>'.print_r($result,1).'</pre>';

Теперь указанный путь возвращается:

Array
(
    [0] => SimpleXMLElement Object
        (
            [actor] => Array
                (
                    [0] => Christian Bale
                    [1] => Liam Neeson
                    [2] => Michael Caine
                )
        )
)

В то время как кажущаяся подобная строка кода, которая у меня была бы, привела бы к певцам, не делает. Имея в виду:

$result = $xml -> xpath('/root/foo:singers');

Результаты в:

Array
    (
        [0] => SimpleXMLElement Object
            (
            )

    )

Теперь я бы подумал, что пространство имен foo: в этом случае не является проблемой, и оба пути должны приводить к тому же массиву исполнителей/актеров соответственно? Почему это не так?

Спасибо!

Примечание. Как вы, вероятно, можете собрать, я совершенно не знаком с xml, поэтому, пожалуйста, будьте осторожны.

Редактировать: Когда я иду /root/foo: певцы/foo: певица, я получаю результаты, но не раньше. Также с помощью just/root я получаю только актеров и предметов в качестве результатов, foo: певцы полностью опущены.

  • 3
    Вы видели несколько таких сообщений? Решение с использованием SimpleXML для получения элементов вне пространства имен по умолчанию - это children() , например var_dump($result[0]->children('foo', true)); Передача префикса пространства имен в качестве первого аргумента и true в качестве второго, чтобы указать, что это префикс, а не полный NS.
  • 1
    Как @MichaelBerkowski уже прокомментировал: вы видите, что элемент не находится в пространстве имен документов по умолчанию . И print_r не особенно полезен с SimpleXMLElement в любом случае, он действительно показывает вам, что находится в пространстве имен по умолчанию в лучшем случае.
Теги:
xpath

2 ответа

2
Лучший ответ

SimpleXML по ряду причин просто плохой API.

Для большинства целей я предлагаю расширение PHP DOM. (Или для очень больших документов комбинация его вместе с XMLReader.)

Для использования пространств имен в xpath вам нужно будет зарегистрировать те, которые вы хотели бы использовать, и префикс, с которым вы хотите их использовать, с вашим процессором xpath.


Пример:

$dom = new DOMDocument();
$dom->load('xpath.xml');
$xpath = new DOMXPath($dom);

// The prefix *can* match that used in the document, but it not necessary.
$xpath->registerNamespace("ns", "http://www.foo.org/");

foreach ($xpath->query("/root/ns:singers") as $node) {
    echo $dom->saveXML($node);
}

Вывод:

<foo:singers>
    <foo:singer id="4">Tom Waits</foo:singer>
    <foo:singer id="5">B.B. King</foo:singer>
    <foo:singer id="6">Ray Charles</foo:singer>
</foo:singers>

DOMXPath :: query возвращает DOMNodeList, содержащий совпадающие узлы. Вы можете работать с ним по существу так же, как и на любом другом языке с реализацией DOM.

  • 0
    Я предлагаю использовать DOMXPath::evaluate() , а не DOMXPath::query() . DOMXPath::query() не поддерживает выражения, которые возвращают скалярные значения, такие как string(/root/ns:singers/ns:singer[@id=5]) .
1

Вы можете использовать // выражение, например:

$xml -> xpath( '//foo:singer' );

чтобы выбрать все элементы foo:singer независимо от того, где они находятся.

РЕДАКТИРОВАТЬ:

Выбрано значение SimpleXMLElement, вы просто не можете видеть дочерние узлы с помощью print_r(). Для доступа к ним используйте методы SimpleXMLElement, такие как SimpleXMLElement :: children.

// example 1
$result = $xml->xpath( '/root/foo:singers' );

foreach( $result as $value ) {
    print_r( $value->children( 'foo', TRUE ) );
}

// example 2
print_r( $result[0]->children( 'foo', TRUE )->singer );
  • 0
    О, нет, я понимаю это, я знаю, как обойти это. Мне просто интересно, почему это происходит. Спасибо :)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню