2012-07-04 51 views
2

我需要通过next_siblingfirst_elt选择下一个节点。但我想通过节点名称来过滤(包含字符串“TON”如何用Perl的XML :: Twig选择兄弟(xpath语法)?

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工艺:/草莓/的Perl /站点/ LIB/XML /枝条。点线3523

回答

3

由于这是通过XML ::嫩枝支持的XPath子集之外,你必须使用一个自定义过滤器,通过将代码first_elt

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

这将返回其子返回的第一个元素真正的价值。

虽然这样的表达需要有点麻烦。在你的例子中,你定义了一个元素类,它们的名字以TON结尾。当你有CARLTON元素时会发生什么?或者当MARRIOTT元素需要用SHERATON和HILTON处理时?你需要重写你的查询吗?

如果你是设计数据格式的人,我会建议修改格式。 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') }) 

这样添加/从其减去其他标签简单。

+0

是提供数据并且不能更改。其实HILTON,SHERATON只是虚拟名称,因为我无法发布原始数据。我目前正在尝试你的解决方案,看起来不错 – laurentngu

2

使用

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

说明

这个表达式使用S上的XPath 1.0 equevalent为的XPath 2.0标准功能ends-with()

中的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属性。

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

+0

非常感谢Xpath 1.0的回答。不幸的是,似乎Perl :: Twig方法(first_elt)不理解这个高级Xpath请求。 '$ t-> parsefile('WO-tampon.xwo'); my $ Y0 = $ t-> first_elt('* [substring(name(),string-length(name()) - 2)=“TON”] [@ method] [1]');'** wrong导航条件'* [substring(name(),string-length(name()) - 2)=“TON”] [@ method] [1]'()at C:/ strawberry/perl/site/lib/XML /Twig.pm line 3523 ** – laurentngu

+0

我将尝试使用xpath请求来支持Xpath 1.0的另一个Perl :: Twig方法:'getNextSibling'。将发布结果 – laurentngu

+0

所有导航方法都使用相同的底层“引擎”,该引擎不支持所有XPath 1.0。也没有在箱子上这么说。如果您需要XPath支持,请使用XML :: Twig :: XPath,那么'findnodes'将为您提供完整的XPath 1.0支持。 – mirod