具有默认名称空间绑定的XML上的PHP xpath查询 [英] PHP xpath query on XML with default namespace binding
问题描述
我对这个问题有一个解决方案,但这是一个hack,我想知道是否有更好的方法可以做到这一点.
I have one solution to the subject problem, but it’s a hack and I’m wondering if there’s a better way to do this.
下面是一个示例XML文件和一个PHP CLI脚本,该脚本执行作为参数给出的xpath查询.对于此测试用例,命令行为:
Below is a sample XML file and a PHP CLI script that executes an xpath query given as an argument. For this test case, the command line is:
./xpeg "//MainType[@ID=123]"
最奇怪的是这条线,没有这条线我的方法将行不通:
What seems most strange is this line, without which my approach doesn’t work:
$result->loadXML($result->saveXML($result));
据我所知,这只是重新解析了修改后的XML,在我看来这不是必须的.
As far as I know, this simply re-parses the modified XML, and it seems to me that this shouldn’t be necessary.
是否有更好的方法在PHP中对此XML执行xpath查询?
Is there a better way to perform xpath queries on this XML in 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脚本:
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);
}
}
}
}
?>
推荐答案
解决方案是使用名称空间,而不是摆脱它.
The solution is using the namespace, not getting rid of it.
$result = new DOMDocument();
$result->loadXML($xml);
$xpath = new DOMXpath($result);
$xpath->registerNamespace("x", trim($argv[2]));
$str = trim($argv[1]);
$result = $xpath->query($str);
并在命令行上这样调用它(请注意XPath表达式中的x:
)
And call it as this on the command line (note the x:
in the XPath expression)
./xpeg "//x:MainType[@ID=123]" "http://www.example.com/data"
您可以通过以下方式使它更加闪亮
You can make this more shiny by
- 自己找出默认的名称空间(通过查看document元素的namespace属性)
- 在命令行上支持多个名称空间,并在
$xpath->query()
之前全部注册它们
-
xyz=http//namespace.uri/
形式的支持参数以创建自定义名称空间前缀
- finding out default namespaces yourself (by looking at the namespace property of the document element)
- supporting more than one namespace on the command line and register them all before
$xpath->query()
- supporting arguments in the form of
xyz=http//namespace.uri/
to create custom namespace prefixes
最底线是:在XPath中,当您真正指的是//namespace:foo
时,您无法查询//foo
.这些根本不同,因此选择不同的节点. XML可以定义默认的名称空间(从而可以在文档中删除显式名称空间使用)这一事实并不意味着您可以在XPath中删除名称空间使用.
Bottom line is: In XPath you can't query //foo
when you really mean //namespace:foo
. These are fundamentally different and therefore select different nodes. The fact that XML can have a default namespace defined (and thus can drop explicit namespace usage in the document) does not mean you can drop namespace usage in XPath.
这篇关于具有默认名称空间绑定的XML上的PHP xpath查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!