加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

使用默认命名空间绑定的XML上的XML xpath查询

发布时间:2020-12-16 23:24:33 所属栏目:百科 来源:网络整理
导读:我有一个主题问题的解决方案,但它是一个黑客,我想知道是否有更好的方法来做到这一点. 下面是一个示例XML文件和一个PHP CLI脚本,它执行作为参数给出的xpath查询.对于此测试用例,命令行是: ./xpeg "//MainType[@ID=123]" 最奇怪的是这条线,没有它我的方法不起
我有一个主题问题的解决方案,但它是一个黑客,我想知道是否有更好的方法来做到这一点.

下面是一个示例XML文件和一个PHP CLI脚本,它执行作为参数给出的xpath查询.对于此测试用例,命令行是:

./xpeg "//MainType[@ID=123]"

最奇怪的是这条线,没有它我的方法不起作用:

$result->loadXML($result->saveXML($result));

据我所知,这只是重新解析修改后的XML,在我看来这不应该是必要的.

有没有更好的方法在PHP中对此XML执行xpath查询?

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脚本:

#!/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 "errorn";
}

// 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 itemsn";
    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 childrenn";
    }
    foreach ($node->childNodes as $child_node) {
      if ($child_node->hasChildNodes()) {
        dump_dom_levels($child_node,$level+1);
      }
    }
  }
}
?>

解决方法

解决方案是使用命名空间,而不是摆脱它.

$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:)

./xpeg "//x:MainType[@ID=123]" "http://www.example.com/data"

你可以让它更闪亮

>自己找出默认命名空间(通过查看文档元素的namespace属性)
>在命令行上支持多个命名空间并在$xpath-> query()之前注册它们
>以xyz = http // namespace.uri /的形式支持参数,以创建自定义名称空间前缀

底线是:在XPath中,当你真正的意思是// namespace:foo时,你无法查询// foo.这些根本不同,因此选择不同的节点. XML可以定义默认名称空间(因此可以删除文档中的显式名称空间使用)并不意味着您可以删除XPath中的名称空间使用.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读