如何使用Perl的XML :: Twig选择兄弟姐妹(xpath语法)?

时间:2012-07-04 21:00:07

标签: perl xpath xml-parsing twig xml-twig

我需要通过 next_sibling first_elt 选择下一个节点。但我想按节点名称(包含字符串“TON”

进行过滤
first_elt ('HILTON[@method]' or 'SHERATON[@method]');

next_sibling ('HILTON[@method]' or 'SHERATON[@method]');

next_sibling ('TON[@method]');

示例我尝试过(不工作):

#!/usr/bin/perl -w
use warnings;
use XML::Twig;
$t-> parsefile ('file.xml');

my $Y0=$t->first_elt('HILTON[@method]' or 'SHERATON[@method]');

它只会处理'HILTON [@method]'

my $Y0=$t->first_elt('/*TON[@method]');

错误导航条件'/ * TON [@method]'()在C:/strawberry/perl/site/lib/XML/Twig.pm第3523行

2 个答案:

答案 0 :(得分:3)

由于这不在XML :: Twig支持的XPath子集中,因此您必须使用自定义过滤器,方法是将代码传递给first_elt

$t->first_elt( sub {  $_[0]->tag=~ m{TON$} && $_[0]->att( 'method') })

这将返回sub返回true值的第一个元素。

这种表达的需要有点令人不安。在您的示例中,您通过其名称以TON结尾的事实来定义一类元素。拥有CARLTON元素会发生什么?或者当需要使用SHERATON和HILTON处理MARRIOTT元素时?你需要重写你的查询吗?

如果您是设计数据格式的人,我建议您修改格式。 HILTON和SHERATON应该是HOTEL,BRAND或OWNER标签的属性。也许一个额外的属性是有用的,以标记两个类型应该类似地处理。只有当它是数据固有的属性时,该属性才有意义。

如果数据是这样的,并且您的格式没有输入,那么我将有一个要处理的标签列表并检查这些:

my %TAGS_TO_PROCESS= map { $_ => 1 } qw( HILTON SHERATON);
my $elt= $t->first_elt( sub {  $TAGS_TO_PROCESS{$_[0]->tag} && $_[0]->att( 'method') })

这样可以轻松添加/减少其他标签。

答案 1 :(得分:2)

使用

*[substring(name(), string-length(name()) - 2) = 'TON'][@method][1]

<强>解释

此表达式对XPath 2.0标准函数ends-with()使用XPath 1.0 equevalent:

XPath 1.0等效的XPath 2.0表达式:

ends-with($s, $s2)

<强>是

substring($s, string-lenth() - string-length($s2) + 1) = $s2

在最后一个表达式中,我们将$s替换为name(),将$s2替换为'TON'

基于XSLT的验证

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="/*">
     <xsl:copy-of select=
     "*[substring(name(), string-length(name()) - 2) = 'TON'][@method] "/>
==========  
     <xsl:copy-of select=
     "*[substring(name(), string-length(name()) - 2) = 'TON'][@method][1] "/>
 </xsl:template>
</xsl:stylesheet>

应用于此XML文档时:

<t>
 <HILTON method="buy"/>
 <TON method="burn"/>
 <TONIC method="drink"/>
 <HILTON nomethod="yes"/>
 <SHERATON/>
 <SHERATON method="visit"/>
</t>

转换会评估两个XPath表达式,并将所选节点复制到输出

<HILTON method="buy"/>
<TON method="burn"/>
<SHERATON method="visit"/>
==========  
     <HILTON method="buy"/>

第一个表达式选择所有元素 - 上下文节点的子节点,其名称以“TON”结尾,并且还具有method属性。

第二个表达式从第一个表达式中选择第一个节点。