perl - 仅选择第一个元素 - 条件使用 XML::Twig

标签 perl xpath xml-twig

拥有此代码:

#!/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>

例如第一个<files> <type> eq 'release' 所在的节点.

根据this answer使用的 XPath 表达式 (//type[string()="release"])[1]/..'应该可以,但似乎我又错过了一些重要的事情。

有人可以帮忙吗?

最佳答案

XML::Twig不支持完整的 XPath 语法。 get_xpath 方法(与 findnodes 相同)的文档说明了这一点

A subset of the XPATH abbreviated syntax is covered:

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_xpathfind_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(),但这纯粹是个人的

关于perl - 仅选择第一个元素 - 条件使用 XML::Twig,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37302855/

相关文章:

c# - stri_replace_all_fixed 相当于 : Replace values based on list

Perl Mojolicious - 如何让它一次处理多个连接?

xml - xsl 1.x如何根据选择更改输出?

html - 具有特定值的任何属性的所有元素的 XPath?

xml - 如何使用 Twig 模块从 XML 中删除注释

perl - XML::Twig keep_encoding 如何工作?

regex - 从正则表达式组中删除某些字符

perl 火狐附加组件

javascript - 是否可以使用 XPath 获取此结果集?

xml - 在 Perl 中组装 XML