使用XML :: LibXML时XML的正确XPath表达式

时间:2016-08-09 09:35:55

标签: perl xpath

我在到达正确的xpath来查询来自xml的数据时遇到了问题。我使用XML::LibXML来执行此操作

XML

<?xml version="1.0" encoding="iso-8859-1"?>
<data>
  <header>
    <date>2016-08-07</date>
    <name>Indices Composites</name>
    <version>1.1a</version>
  </header>
  <row>
    <CompositePrice>1.010227784212584</CompositePrice>
    <CompositeSpread>0.002568273865609903</CompositeSpread>
    <Date>2016-08-05</Date>
    <Depth>4</Depth>
    <Heat>0.0201994587386602</Heat>
    <IndexID>ITRAXX-SOVXWES8V1-5Y</IndexID>
    <Maturity>2017-12-20</Maturity>
    <ModelPrice>1.0103988929051526</ModelPrice>
    <ModelSpread>0.002445016658588964</ModelSpread>
    <Name>iTraxx SovX Westn Europe</Name>
    <OnTheRun>Y</OnTheRun>
    <REDCode>5C769MAO9</REDCode>
    <RequestKey>iTraxx SovX Westn Europe|5Y|Y</RequestKey>
    <Series>8</Series>
    <ShortName></ShortName>
    <Term>5Y</Term>
    <Version>1</Version>
  </row>
  <row>
    <CompositePrice>1.0208723593556004</CompositePrice>
    <CompositeSpread>0.006539233068666665</CompositeSpread>
    <Date>2016-08-05</Date>
    <Depth>3</Depth>
    <Heat>0.0307106033333336</Heat>
    <IndexID>ITRAXX-SOVXWES8V1-10Y</IndexID>
    <Maturity>2022-12-20</Maturity>
    <ModelPrice>1.0219657857189512</ModelPrice>
    <ModelSpread>0.006361337372712667</ModelSpread>
    <Name>iTraxx SovX Westn Europe</Name>
    <OnTheRun>Y</OnTheRun>
    <REDCode>5C769MAO9</REDCode>
    <RequestKey>iTraxx SovX Westn Europe|10Y|Y</RequestKey>
    <Series>8</Series>
    <ShortName></ShortName>
    <Term>10Y</Term>
    <Version>1</Version>
  </row>
</data>

我需要根据某些标签的值进行过滤。代码如下所示。

my $parser = XML::LibXML->new;

my $doc = $parser->parse_file($inputFile);

my @nodes = $doc->findnodes("/data/row/Name[text()='iTraxx SovX Westn Europe']/../Term[text()='5Y']/../OnTheRun[text()='Y']");

print "@nodes \n";

我得到的输出是

<OnTheRun>Y</OnTheRun>

而我希望得到满足条件的整个节点。

XPath表达式就在这里吗?

1 个答案:

答案 0 :(得分:3)

XPath表达式非常类似于Linux文件路径。如果从所写的内容中删除所有谓词,则得到

/data/row/Name/../Term/../OnTheRun

您可以在此处看到,从row元素开始,您将升入Name并返回一个级别,然后返回Term并返回一个级别,最后进入OnTheRun,其中表达式停止

这就是为什么您只看到OnTheRun元素的值,一个简单的修复方法是添加另一个..路径步骤以返回到您的row元素想要访问

这个XPath表达式工作正常

/data/row/Name[text()='iTraxx SovX Westn Europe']/../Term[text()='5Y']/../OnTheRun[text()='Y']/..

但阅读

非常尴尬

我认为最好的方法是将多个谓词应用到主/data/row选择器,就像这样

/data/row[Name="iTraxx SovX Westn Europe"][Term="5Y"][OnTheRun="Y"]

这是一个完整的程序,用它来处理您的样本数据

use strict;
use warnings 'all';
use open IO  => ":encoding(iso-8859-1)";

use XML::LibXML;

my $doc = XML::LibXML->load_xml( location => 'indices_composites.xml' );

my @nodes = $doc->findnodes('/data/row[Name="iTraxx SovX Westn Europe"][Term="5Y"][OnTheRun="Y"]');

printf "%d node%s found:\n\n", scalar @nodes, @nodes == 1 ? '' : 's';

print $nodes[0], "\n";

输出

1 node found:

<row>
    <CompositePrice>1.010227784212584</CompositePrice>
    <CompositeSpread>0.002568273865609903</CompositeSpread>
    <Date>2016-08-05</Date>
    <Depth>4</Depth>
    <Heat>0.0201994587386602</Heat>
    <IndexID>ITRAXX-SOVXWES8V1-5Y</IndexID>
    <Maturity>2017-12-20</Maturity>
    <ModelPrice>1.0103988929051526</ModelPrice>
    <ModelSpread>0.002445016658588964</ModelSpread>
    <Name>iTraxx SovX Westn Europe</Name>
    <OnTheRun>Y</OnTheRun>
    <REDCode>5C769MAO9</REDCode>
    <RequestKey>iTraxx SovX Westn Europe|5Y|Y</RequestKey>
    <Series>8</Series>
    <ShortName/>
    <Term>5Y</Term>
    <Version>1</Version>
  </row>