使用XML :: LibXML在Perl中使用XPath检查属性的特定值并提取sibblings值

时间:2012-11-06 05:46:09

标签: perl xpath libxml2

如果solveuser,则需要nameLINES)的值。

如果solveimm且名称为ARCH,则需要value6M)的值

我尝试了以下内容:

use strict;
use warnings;
use XML::LibXML;
my $parser = XML::LibXML->new();
my $doc = $parser->parse_file(...);
my $j = 0;
my @imm;
$imm[$j++] = $_->data
    foreach 
        $doc->findnodes(
            "//meters/meter"
            ."/name[../value[\@solve/string() = 'immediate']]"
            ."/text()");

错误是

Possible unintended interpolation of @solve in string
Global symbol "@solve" requires explicit package name 

示例XML:

<rules> 
      <meters>        
             <meter>
                   <name>LINES</spirit:name>
                   <display>LINES</display>
                   <description>Specifies the number of lines</description>
                   <value
                         solve="user"
                         id="LINES"
                         order="11"
                         format="long"
                         dataType="integer" 
                         min="2" 
                         max="34">34</value>
            </meter>
            <meter>
                  <name>ARCH</name>
                  <display>Define ARCH</display>
                  <description>Define ARCH</description>
                  <value 
                        format="string" 
                        solve="imm" 
                        id="ARCH" 
                        >6M</value>
             </meter>
       </meters>    
</rules>

<rules> 
      <meters>        
             <meter>
                   <name>LINES</spirit:name>
                   <display>LINES</display>
                   <description>Specifies the number of lines</description>
                   <value
                         solve="user"
                         id="LINES"
                         order="11"
                         format="long"
                         dataType="integer" 
                         min="2" 
                         max="34">34</value>
            </meter>
            <meter>
                  <name>ARCH</name>
                  <display>Define ARCH</display>
                  <description>Define ARCH</description>
                  <value 
                        format="string" 
                        solve="imm" 
                        id="ARCH" 
                        >6M</value>
             </meter>
       </meters>    
</rules>

2 个答案:

答案 0 :(得分:1)

快速而肮脏的黑客来解决您的问题 - 使用XML::Simple

use strict;
use warnings;

use XML::Simple ;
use Data::Dumper;

my $xml = XMLin(qq|
<xml>
<rules> 
      <meters>        
             <meter>
                   <name>LINES</name>
                   <display>LINES</display>
                   <description>Specifies the number of lines</description>
                   <value
                         solve="user"
                         id="LINES"
                         order="11"
                         format="long"
                         dataType="integer" 
                         min="2" 
                         max="34">34</value>
            </meter>
            <meter>
                  <name>ARCH</name>
                  <display>Define ARCH</display>
                  <description>Define ARCH</description>
                  <value 
                        format="string" 
                        solve="imm" 
                        id="ARCH" 
                        >6M</value>
             </meter>
       </meters>    
</rules>

<rules> 
      <meters>        
             <meter>
                   <name>LINES</name>
                   <display>LINES</display>
                   <description>Specifies the number of lines</description>
                   <value
                         solve="user"
                         id="LINES"
                         order="11"
                         format="long"
                         dataType="integer" 
                         min="2" 
                         max="34">34</value>
            </meter>
            <meter>
                  <name>ARCH</name>
                  <display>Define ARCH</display>
                  <description>Define ARCH</description>
                  <value 
                        format="string" 
                        solve="imm" 
                        id="ARCH" 
                        >6M</value>
             </meter>
       </meters>    
</rules>
</xml>|,
ForceArray => 1);

foreach my $rule( @{ $xml->{rules} } ){
  foreach my $meter ( @{ $rule->{meters} } ){
    foreach my $m ( @{ $meter->{meter} } ){    
      if ( $m->{value}->{LINES} and $m->{value}->{LINES}->{solve} eq 'user' ) {
        print "user solver: ".$m->{name}->[0]."\n";
      } elsif ( $m->{value}->{ARCH}->{solve} and $m->{name}->[0] and $m->{value}->{ARCH}->{solve} eq 'imm' and $m->{name}->[0] eq 'ARCH' ) {
        print "imm solver: ".Dumper( $m->{value}->{ARCH}->{content})."\n";
      } else {
        print "no solver???".Dumper($m);
      }
    }    
  }
}

我希望你能以此为出发点。

<强>观察

  • 鉴于foreach es只包含一条指令(if),它们可以重写为maps,但我不鼓励
  • if也可以使用ternary operatorprint结果字符串重写
  • 考虑到上述所有情况,整个XML处理可以在一行中重写,包括3个map和2个三元操作 - 我认为这几乎是不可读的

答案 1 :(得分:1)

这对我有用:

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

use XML::LibXML;

my $parser = XML::LibXML->new();
my $doc = $parser->parse_file('XXX.xml');
my $j = 0;
my @imm;
$imm[$j++] = $_->data
    for $doc->findnodes(
            "//meters/meter"
            ."/name[../value[\@solve = 'imm']]"
            ."/text()");
print for @imm;

我对您的代码进行了以下更改:

  1. 我从XPath表达式中删除了/string()部分。它是对我所得到的错误所指示的函数的无效使用。
  2. 示例数据中solve的值为imm,而不是immediate
  3. BTW,将XPath表达式的中间位置改为

    '/name[../value[@solve = "immediate"]]'
    

    避免使用反斜杠。