Perl libxml findvalue 在根标签包含属性时失败

Perl libxml findvalue fails when root tag contains attributes

提问人:Andreas 提问时间:4/26/2023 最后编辑:toolicAndreas 更新时间:4/26/2023 访问量:62

问:

我正在尝试过滤给定 XML 文件中与 CSV 文件中包含的合同 ID 匹配的记录。

xml 文件如下所示:

<ROOTS02 xmlns="http://www.fja.com/RAN/RANTS02" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.fja.com/RAN/RANTS02 RANTS02.xsd">
<Record>
<Date>27.02.2023</Date>
<Year>2022</Year>
<ContractID>115000520</ContractID>
<Data>
... some more fields ...
</Data>
</Record>
<Record>
</Record>
....
</ROOTS02>

我的 perl 代码如下所示:

#!/usr/bin/perl -w
use strict;
use XML::LibXML;
my $xml_parser = XML::LibXML->new();

my $xml_file="data0.xml";
my $vidfile="contractids.txt";
my $output="out0.xml";
my $roottag='ROOTS02';
my $rectag='Record';
my $filtertag='ContractID';
my $element;
my %vidtable;



readcontractids($vidfile);

print "Parsing input file $xml_file....";
my $xml_doc = $xml_parser->parse_file($xml_file);
#parsefile($input);
my $root = $xml_doc->documentElement();
my @records = $root->getElementsByTagName($rectag);
open(OUT, '>:encoding(UTF-8)', $output);
foreach my $record (@records) {
    my $contract_id = $record->findvalue($filtertag);
    if ( exists $vidtable{$contract_id} ) {
        $record->unbindNode();
        print OUT $record->toString();
    }
}
close OUT;
print "Done!\n";
print "Output written to $output\n";

###########################################
sub readvertragids {
   my $file=shift;
   my $pidold;
   my $pidnew;
   open(FH, '<', $file) or die "Error: $file can't be read :$!";
   while (<FH>) {
      chomp $_;
      if ( ! exists $vidtable{$_} ) {
         $vidtable{$_}=$_;
      }
   }
   close(FH);
}

如果从 XML 文件第一行的 ROOTS02 标记中删除属性,一切正常:

对于包含属性的 XML 文件的原始第一行,对标记“ContarctID”的 findvalue 调用没有结果:

perl -d ./t5.pl 

Loading DB routines from perl5db.pl version 1.37
Editor support available.

Enter h or 'h h' for help, or 'man perldebug' for more help.

main::(./t5.pl:4):      my $xml_parser = XML::LibXML->new();
  DB<1> b 56
  DB<2> r
main::(./t5.pl:56):         if ( exists $vidtable{$contract_id} ) {
  DB<2> Parsing input file rant0.xml....l 50-60
50      #parsefile($input);
51:     my $root = $xml_doc->documentElement();
52:     my @records = $root->getElementsByTagName($rectag);
53:     open(OUT, '>:encoding(UTF-8)', $output);
54:     foreach my $record (@records) {
55:         my $contract_id = $record->findvalue($filtertag);
56==>b      if ( exists $vidtable{$contract_id} ) {
57:             $record->unbindNode();
58:             print OUT $record->toString();
59          }
60      }
  DB<3> p $rectag
Record
  DB<4> p $filtertag
ContractID
  DB<5> p $contract_id

  DB<6> p $record
<Record>
<Date>27.02.2023</Date>
<Year>2022</Year>
<ContractID>115000520</ContractID>
...

我该怎么做才能使它甚至与根标签中的属性一起工作? 这些属性对 libxml 函数的功能有何影响?

perl libxml2

评论

0赞 UncleCarl 4/26/2023
我不希望这将是一个解决方案,但我没有找到 .我使用 .parse_filemy $dom = XML::LibXML->load_xml( location => $filename );
0赞 ikegami 4/26/2023
@UncleCarl,XML::LibXML 类记录在 XML::LibXML::P arser 中。在这里,您可以找到类方法和 以及实例方法的文档。newload_xmlparse_file
0赞 UncleCarl 4/26/2023
@ikegami是的。我想我需要进一步深入到XML文档汤中。我想类方法对我来说效果更好,至少在只处理单个文件时是这样。
0赞 Gilles Quénot 4/26/2023
@UncleCarl:我猜是这样。parse_fileFile::Slurp
0赞 ikegami 4/26/2023
@Gilles Quénot,没有。与 File::Slurp 无关。如上所述,这是一个 XML::LibXML 方法。 事实上,早于。->new->parse_file->load_xml

答:

3赞 ikegami 4/26/2023 #1

[我将使用 {namespace} 名称表示法。]

您正在寻找一个节点。{}ContractID

但文档中的节点是节点。{http://www.fja.com/RAN/RANTS02}ContractID

这是因为设置了关联元素的默认命名空间,以及所有后代元素。xmlns=""

use XML::LibXML qw( );

my $xpc = XML::LibXML::XPathContext->new();
$xpc->registerNs( r => "http://www.fja.com/RAN/RANTS02" );

my $doc = XML::LibXML->new->parse_file( "data0.xml" );

for my $rec_node ( $xpc->findnodes( "/r:ROOTS02/r:Record", $doc ) ) {
   my $contract_id = $xpc->findvalue( "r:ContractID", $rec_node );
   ...
}

评论

0赞 Andreas 4/27/2023
它有效!非常感谢!但是,还有一个额外的问题:是否有更通用的方法来在 findvalue 调用中指定标记或路径?我在记录中包含附加级别的类似 xml 文件时遇到了问题:“'' <ROOTS02 xmlns=”fja.com/RAN/RANTS02“ ....”> <Record> <Header> <Date>27.02.2023</Date> <Year>2022</Year> <ContractID>115000520</ContractID> </Header> <Data> ...还有一些领域......</data> </record> <record> </record>....</ROOTS02> '''
0赞 ikegami 4/27/2023
.//r:Recorddescendant::r:Record