【问题标题】:XML::Twig::XPath: `findnodes` still compains I should use `findnodes` instead of `get_xpath`XML::Twig::XPath: `findnodes` 仍然存在我应该使用 `findnodes` 而不是 `get_xpath`
【发布时间】:2021-11-05 21:49:50
【问题描述】:

我编写了一些构建 XML::Twig 树的 Perl 模块。 不幸的是,XML::Twig 的 XPath 实现似乎不完整,所以我加载了XML::Twig::XPath

由于 XML::Twig 的文档指出 findnodesget_xpath 相同(还有更多),我期待我可以处理像 //info_string[text()] 这样的查询,而原始 XML::Twig 没有喜欢。

在第一次运行时,XML::Twig::XPath 抱怨我必须使用 getnodes 而不是 get_xpath,所以我改变了它。

不幸的是,即使在更改之后,我仍然收到相同的消息:

error in xpath expression //info_string[text()] at text()
the expression is a valid XPath statement, and you are using XML::Twig::XPath, but
you are using either 'find_nodes' or 'get_xpath' where the method you likely wanted
to use is 'findnodes', which is the only one that uses the full XPath engine
 at /usr/lib/perl5/vendor_perl/5.18.2/XML/Twig.pm line 3566.

我很困惑。

有问题的语句如下所示:

return $self->_XML()->findnodes($XPath);

_XML() 方法返回 XML::Twig 树,findnodes 预计会查询该树。

我也尝试将use XML::Twig 替换为use XML::Twig::XPath,但这也没有改变消息。

详情

由于创建数据结构和从中创建 XML 的代码过于复杂,我将在此处展示 XML 输出 ($self->_XML()->print) 和数据结构 (通过 Data::Dumper)。

要查询的 XML 如下所示:

<MonitoringOutput id="test-id" version="0.1">
  <description>This is a test output</description>
  <exit_code>0</exit_code>
  <status_string>OK</status_string>
  <info_string>(demo): Some interesting story</info_string>
  <perf_string>L1=0.49 L2=4.7s;;;0;7 L3=0.6;@0.2:0.3</perf_string>
  <perf_data count="3">
    <sample label="L3">
      <label>L3</label>
      <value>0.6</value>
      <thresholds>
        <warn end="0.3" inverted="1" start="0.2"/>
      </thresholds>
    </sample>
    <sample label="L1">
      <label>L1</label>
      <value>0.49</value>
    </sample>
    <sample label="L2">
      <label>L2</label>
      <value unit="s">4.7</value>
      <unit>s</unit>
      <range max="7" min="0"/>
    </sample>
    <warn_labels count="0"/>
    <crit_labels count="0"/>
  </perf_data>
</MonitoringOutput>

这是我尝试制作一个可重现的最小示例:

#!/usr/bin/perl
use warnings;
use strict;

use XML::Twig;
use XML::Twig::XPath;

my $twig = XML::Twig->new();
$twig->parse('<MonitoringOutput id="test-id" version="0.1">
  <description>This is a test output</description>
  <exit_code>0</exit_code>
  <status_string>OK</status_string>
  <info_string>(demo): Some interesting story</info_string>
  <perf_string>L1=0.49 L2=4.7s;;;0;7 L3=0.6;@0.2:0.3</perf_string>
  <perf_data count="3">
    <sample label="L3">
      <label>L3</label>
      <value>0.6</value>
      <thresholds>
        <warn end="0.3" inverted="1" start="0.2"/>
      </thresholds>
    </sample>
    <sample label="L1">
      <label>L1</label>
      <value>0.49</value>
    </sample>
    <sample label="L2">
      <label>L2</label>
      <value unit="s">4.7</value>
      <unit>s</unit>
      <range max="7" min="0"/>
    </sample>
    <warn_labels count="0"/>
    <crit_labels count="0"/>
  </perf_data>
</MonitoringOutput>');
$twig->findnodes('//info_string[text()]');

在调试器下运行它时(在具有更新 perl 的不同机器上),我得到以下输出:

error in xpath expression //info_string[text()] at text()
the expression is a valid XPath statement, and you are using XML::Twig::XPath, but
you are using either 'find_nodes' or 'get_xpath' where the method you likely wanted
to use is 'findnodes', which is the only one that uses the full XPath engine
 at /usr/lib/perl5/vendor_perl/5.26.1/XML/Twig.pm line 3685.
 at /usr/lib/perl5/vendor_perl/5.26.1/XML/Twig.pm line 7122.
    XML::Twig::Elt::_croak_and_doublecheck_xpath("//info_string[text()]", "error in xpath expression //info_string[text()] at text()") called at /usr/lib/perl5/vendor_perl/5.26.1/XML/Twig.pm line 7089
    XML::Twig::Elt::_install_xpath("//info_string[text()]") called at /usr/lib/perl5/vendor_perl/5.26.1/XML/Twig.pm line 7131
    XML::Twig::Elt::get_xpath(XML::Twig::Elt=HASH(0x5591017d3da0), "//info_string[text()]") called at /usr/lib/perl5/vendor_perl/5.26.1/XML/Twig.pm line 3685
    XML::Twig::get_xpath(XML::Twig=HASH(0x55910059bb00), "//info_string[text()]") called at /tmp/t.pl line 38

【问题讨论】:

  • 请向我们展示您的 XML 示例。
  • @Dada 您需要将 XML 作为文本还是作为 Perl 结构?关于查询:模式取自w3schools.com/xml/xpath_examples.asp
  • 我们真正需要的是Minimal, Reproducible Example。例如,一个小的 XML 输入,您的代码读取该输入并创建一个 XML::Twig 对象,然后查询不起作用。
  • 我已按要求添加了详细信息。我仍然认为ref $self-&gt;_XML() 的输出就足够了。
  • 正如@Dada 所提到的,如果您可以构建一个可运行的示例,那就太好了。这将有助于澄清您的问题,我们可以尝试重现您观察到的行为

标签: perl xpath xml-twig


【解决方案1】:

在构造树枝对象时,您似乎需要使用XML::Twig::XPath(而不是XML::Twig)。以下对我有用:

my $twig = XML::Twig::XPath->new();
$twig->parse( .... );
$twig->findnodes('//info_string[text()]');

【讨论】:

  • 我将离开我的源代码一段时间(9 月底),所以我得稍后再检查。然而,真正的 XML 树的构造当然是不同的。您是否同意错误消息至少令人困惑?
  • 在构造函数中将XML::Twig 替换为XML::Twig::XPath 时,原始错误消息消失了,但在进一步测试中我得到了Can't locate object method "node_cmp" via package "XML::Twig::Elt" ...。我的代码也使用构造函数XML::Twig::Elt-&gt;new 添加元素。我尝试使用$twig 使用elt_class,但失败了(对象方法未知)。
【解决方案2】:

在构建具有完整 XPath 支持的 XML 树时,必须使用 XML::Twig::XPath-&gt;new 构建它并且 添加的元素必须使用 XML::Twig::XPath::Elt-&gt;new 创建以使 findnodes 工作。

由于在我的代码中使用 XPath 是一种可选操作,因此我决定动态加载 XML::TwigXML::Twig::XPath,这取决于是否需要完整的 XPath 支持。 此外,我的代码必须使用 XML::Twig::XPath::Elt 而不是 XML::Twig::Elt 以获得完整的 XPath 支持。

所以我的代码使用了这些技巧:

my $xml_twig = $use_xpath ? 'XML::Twig::XPath' : 'XML::Twig';
my $xml_twig_mod = $xml_twig . '.pm';
$xml_twig_mod =~ s,::,/,g;
require $xml_twig_mod;
my $xml = $xml_twig->new(...);
my $elt = "${xml_twig}::Elt"->new(...);

另见https://stackoverflow.com/a/5790563/6607497

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-10
    • 1970-01-01
    • 1970-01-01
    • 2015-10-25
    • 1970-01-01
    • 2012-06-04
    • 1970-01-01
    • 2018-04-28
    相关资源
    最近更新 更多