首页 > 解决方案 > 具有冲突的 XML 命名空间前缀的 XPath 行为

问题描述

考虑以下 XML:

<?xml version="1.0" encoding="utf-8"?>
<movies xmlns:en="http://english-language.com/">
    <en:movie>
        <title>The Godfather</title>
    </en:movie>
    <en:movie>
        <title>Saving Private Ryan</title>
    </en:movie>
    <something-something xmlns:en="http://english.com/">
        <en:movie>
            <title>The Fellowship of the Ring</title>
        </en:movie>
    </something-something>
</movies>

下面的代码将匹配教父拯救大兵瑞恩。但为什么?我预计它会失败。似乎该查询忽略了命名空间名称 (URI) 以支持命名空间前缀

$xpath      = new DOMXpath($dom);
$xpath->registerNamespace('en', 'http://complete-nonsense');
$elements   = $xpath->query("//en:movie");

我希望下面的代码与The Fellowship of the Ring相匹配,但它再次与教父拯救大兵瑞恩相匹配。

$xpath      = new DOMXpath($dom);
$xpath->registerNamespace('en', 'http://english.com/');
$elements   = $xpath->query("//en:movie");

只是现在 URI 似乎有所不同,现在它与The Fellowship of the Ring相匹配。

$xpath      = new DOMXpath($dom);
$xpath->registerNamespace('english', 'http://english.com/');
$elements   = $xpath->query("//english:movie");

这是为什么?PHP的实现有问题还是什么?

标签: phpxmldomxpath

解决方案


DOMXpath::evaluate()/DOMXpath::query()在手动注册的之上注册当前上下文节点的命名空间定义。基本上,文档将覆盖前缀的命名空间。第三个参数(因为 PHP >= 5.3.3)可以禁用自动注册:

$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);
$xpath->registerNamespace('en', 'http://english.com/');

// the xmlns:en from the document element overrides the registration
var_dump($xpath->evaluate('normalize-space(//en:movie)'));
// automatic registration disabled - works correctly
var_dump($xpath->evaluate('normalize-space(//en:movie)', NULL, FALSE));

输出:

string(13) "The Godfather"
string(26) "The Fellowship of the Ring"

推荐阅读