如何使用phpstorm评估特定namesapce的xpath?

时间:2015-09-22 13:07:03

标签: php xml xpath settings phpstorm

欧洲中央银行提供XML document for currency exchange rates欧元的依赖。

<?xml version="1.0" encoding="UTF-8"?>
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
    <gesmes:subject>Reference rates</gesmes:subject>
    <gesmes:Sender>
        <gesmes:name>European Central Bank</gesmes:name>
    </gesmes:Sender>
    <Cube>
        <Cube time='2015-09-17'>
            <Cube currency='USD' rate='1.1312'/>
            <Cube currency='JPY' rate='136.76'/>
            <Cube currency='BGN' rate='1.9558'/>
            ...
        </Cube>
    </Cube>
</gesmes:Envelope>

我已将此XML文件存储为货币汇率提供程序的测试用例,因为我想为其编写解析器。

我想使用phpstorm&#39; Evaluate XPath...功能。

但它似乎并没有认识到命名空间;所以找不到//Cube的任何匹配。

Evaluate XPath window

我也尝试使用Show unique XPath,对我来说它显示

/gesmes:Envelope/e:Cube/e:Cube/e:Cube/@rate

然而,在没有回复的情况下使用它来评估收益率。

我想我的配置错误(因为我试图编辑上下文,但我不知道我在做什么)。

Edit Xpath Context

如何设置正确的命名空间?

2 个答案:

答案 0 :(得分:2)

您在Xpath表达式中为名称空间e使用了前缀http://www.ecb.int/vocabulary/2002-08-01/eurofxref,但为其配置了前缀c

您不需要在PHP中为它编写解析器。只需使用DOM + Xpath。

$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
$xpath->registerNamespace('gesmes', 'http://www.gesmes.org/xml/2002-08-01');
$xpath->registerNamespace('e', 'http://www.ecb.int/vocabulary/2002-08-01/eurofxref');

$time = $xpath->evaluate('string(/gesmes:Envelope/e:Cube/e:Cube/@time)');

$rates = [];
foreach ($xpath->evaluate('/gesmes:Envelope/e:Cube/e:Cube/e:Cube') as $cube) {
  $rates[$cube->getAttribute('currency')] = $cube->getAttribute('rate');
}

var_dump($time, $rates);

输出:

string(10) "2015-09-22"
array(31) {
  ["USD"]=>
  string(6) "1.1155"
  ["JPY"]=>
  string(6) "133.75"
  ["BGN"]=>
  string(6) "1.9558"
  ["CZK"]=>
  string(6) "27.057"
  ["DKK"]=> ...

答案 1 :(得分:0)

您需要告诉XPath哪些命名空间绑定到哪些前缀,或者为表达式中未加前缀的名称设置默认命名空间。并非所有主机语言都支持此设置。

在PHPStorm中,您可以通过单击按钮编辑上下文... see documentation来执行此操作。

如果由于某种原因,您无法正确设置,可以使用名称的本地名称进行查询,您的查询将变为:

/*[local-name() = 'Envelope']
    /*[local-name() = 'Cube']
    /*[local-name() = 'Cube']
    /*[local-name() = 'Cube']/@rate

不理想,但它会起作用。

⑴任何XML名称都包含一个本地部分,如果没有冒号,则是冒号或整个名称后的部分,前缀部分(冒号前面的部分)和命名空间部分(是前缀绑定的命名空间。 XML名称由local-name及其名称空间确定性地定义,前缀无关紧要。