拥有此代码:
#!/usr/bin/env perl
use 5.014;
use warnings;
use XML::Twig;
my $twig = XML::Twig->parse( \*DATA );
$twig->set_pretty_print('indented_a');
# 1st search
# this prints OK the all <files> nodes where the <type> == 'release'
$_->print for ( $twig->findnodes( '//type[string()="release"]/..' ) );
# 2nd search
# try to get first matched only
my $latest = $twig->findnodes( '(//type[string()="release"])[1]/..' );
$latest->print;
__DATA__
<root>
<files>
<type>beta</type>
<ver>3.0</ver>
</files>
<files>
<type>alpha</type>
<ver>3.0</ver>
</files>
<files>
<type>release</type>
<ver>2.0</ver>
</files>
<files>
<type>release</type>
<ver>1.0</ver>
</files>
</root>
以上打印
<files>
<type>release</type>
<ver>2.0</ver>
</files>
<files>
<type>release</type>
<ver>1.0</ver>
</files>
error in xpath expression (//type[string()="release"])[1]/.. around (//type[string()="release"])[1]/.. at /opt/anyenv/envs/plenv/versions/5.24.0/lib/perl5/site_perl/5.24.0/XML/Twig.pm line 3648.
第二次搜索所需的输出
<files>
<type>release</type>
<ver>2.0</ver>
</files>
e.g。 <files>
。
<type> eq 'release'
节点
根据this answer使用的XPath表达式(//type[string()="release"])[1]/..'
应该有效,但似乎我再次错过了一些重要的内容。
有人可以帮忙吗?
答案 0 :(得分:4)
XML::Twig
不支持完整的XPath语法。 get_xpath
方法的文档(与findnodes
相同)说明了这个
涵盖了XPATH缩写语法的一个子集:
tag tag[1] (or any other positive number) tag[last()] tag[@att] (the attribute exists for the element) tag[@att="val"] tag[@att=~ /regexp/] tag[att1="val1" and att2="val2"] tag[att1="val1" or att2="val2"] tag[string()="toto"] (returns tag elements which text (as per the text method) is toto) tag[string()=~/regexp/] (returns tag elements which text (as per the text method) matches regexp) expressions can start with / (search starts at the document root) expressions can start with . (search starts at the current element) // can be used to get all descendants instead of just direct children * matches any tag
因此不支持括号内的子表达式,并且您只能指定一个谓词
同样重要的是,在标量上下文中,findnodes
只会返回找到的节点数的计数。您必须在列表上下文中使用它来检索节点本身,这意味着找到第一个匹配元素的更简单方法是编写
my ($latest) = $twig->findnodes( '//type[string()="release"]/..' );
工作正常
如果您真的需要XPath的全部功能,那么您可以使用XML::Twig::XPath
代替。此模块使用XML::XPath
或优秀XML::XPathEngine
来通过重载findnodes
来提供完整的XPath语法。 (其他方法get_xpath
和find_nodes
继续使用缩减的XML::Twig
变体。)
findnodes
现在返回一个XML::XPathEngine::NodeSet
对象,该对象具有重载的数组索引。所以你可以写
my $latest = $twig->findnodes( '//type[string()="release"]/..' );
$latest->[0]->print;
或只是
my ($latest) = $twig->findnodes( '//type[string()="release"]/..' );
如上所述。
最后,我希望看到/root/files[type[string()="release"]]
优先于尾随parent::node()
,但这纯属个人
答案 1 :(得分:3)
XML :: Twig不支持所有XPath,但XML :: Twig :: XPath支持。
所以use XML::Twig::XPath;
,然后是my $twig = XML::Twig::XPath->parse(...
并且vo ...你现在可以修复$latest=...
行,它应该是:
my $latest = ($twig->findnodes( '(//type[string()="release"])[1]/..' ))[0];
(你拥有它的最新方式是XML::XPathEngine::NodeSet
,你需要获取该组的第一个元素。)
答案 2 :(得分:2)