У меня есть одно решение данной проблемы, но это взлом, и мне интересно, есть ли лучший способ сделать это.
Ниже приведен пример XML-файла и сценарий PHP CLI, который выполняет запрос xpath, указанный в качестве аргумента. Для этого тестового примера командная строка:
./xpeg "//MainType[@ID=123]"
Что кажется наиболее странным, так это строка, без которой мой подход не работает:
$result->loadXML($result->saveXML($result));
Насколько я знаю, это просто повторно анализирует модифицированный XML, и мне кажется, что в этом не должно быть необходимости.
Есть ли лучший способ выполнять запросы xpath для этого XML в PHP?
XML ( обратите внимание на привязку пространства имен по умолчанию ):
<?xml version="1.0" encoding="utf-8"?>
<MyRoot
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.example.com/data http://www.example.com/data/MyRoot.xsd"
xmlns="http://www.example.com/data">
<MainType ID="192" comment="Bob's site">
<Price>$0.20</Price>
<TheUrl><![CDATA[http://www.example.com/path1/]]></TheUrl>
<Validated>N</Validated>
</MainType>
<MainType ID="123" comment="Test site">
<Price>$99.95</Price>
<TheUrl><![CDATA[http://www.example.com/path2]]></TheUrl>
<Validated>N</Validated>
</MainType>
<MainType ID="922" comment="Health Insurance">
<Price>$600.00</Price>
<TheUrl><![CDATA[http://www.example.com/eg/xyz.php]]></TheUrl>
<Validated>N</Validated>
</MainType>
<MainType ID="389" comment="Used Cars">
<Price>$5000.00</Price>
<TheUrl><![CDATA[http://www.example.com/tata.php]]></TheUrl>
<Validated>N</Validated>
</MainType>
</MyRoot>
PHP CLI Script:
#!/usr/bin/php-cli
<?php
$xml = file_get_contents("xpeg.xml");
$domdoc = new DOMDocument();
$domdoc->loadXML($xml);
// remove the default namespace binding
$e = $domdoc->documentElement;
$e->removeAttributeNS($e->getAttributeNode("xmlns")->nodeValue,"");
// hack hack, cough cough, hack hack
$domdoc->loadXML($domdoc->saveXML($domdoc));
$xpath = new DOMXpath($domdoc);
$str = trim($argv[1]);
$result = $xpath->query($str);
if ($result !== FALSE) {
dump_dom_levels($result);
}
else {
echo "error\n";
}
// The following function isn't really part of the
// question. It simply provides a concise summary of
// the result.
function dump_dom_levels($node, $level = 0) {
$class = get_class($node);
if ($class == "DOMNodeList") {
echo "Level $level ($class): $node->length items\n";
foreach ($node as $child_node) {
dump_dom_levels($child_node, $level+1);
}
}
else {
$nChildren = 0;
foreach ($node->childNodes as $child_node) {
if ($child_node->hasChildNodes()) {
$nChildren++;
}
}
if ($nChildren) {
echo "Level $level ($class): $nChildren children\n";
}
foreach ($node->childNodes as $child_node) {
if ($child_node->hasChildNodes()) {
dump_dom_levels($child_node, $level+1);
}
}
}
}
?>