Я изучаю 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: певцы полностью опущены.
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.
DOMXPath::evaluate()
, а не DOMXPath::query()
. DOMXPath::query()
не поддерживает выражения, которые возвращают скалярные значения, такие как string(/root/ns:singers/ns:singer[@id=5])
.
Вы можете использовать //
выражение, например:
$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 );
children()
, напримерvar_dump($result[0]->children('foo', true));
Передача префикса пространства имен в качестве первого аргумента иtrue
в качестве второго, чтобы указать, что это префикс, а не полный NS.print_r
не особенно полезен с SimpleXMLElement в любом случае, он действительно показывает вам, что находится в пространстве имен по умолчанию в лучшем случае.