How to filter out nodes from an XML using PERL scr

2019-10-22 06:30发布

这个问题是所有在互联网上,但是我看到的例子不考虑我显然独特情况。 下面是我的XML的摘录:

<message type="error" from="Realtime" timestamp="Mon Nov 24 19:28:55 2014"> Could not receive from Loader </message>
<message type="warning" from="Dcd_Mux" timestamp="Mon Dec  1 02:31:18 2014"> Could not connect to Dcd </message>

相反,具有节点的几个层次的,我只是有一个消息节点上几个属性。 我希望能够基于一个参数,以我的Perl脚本过滤掉的节点。 例如:如果我想要类型为“错误”,以滤除所有的消息,我是使用XML,只有具有从上面的2行,我的输出将仅由上述警告消息。 这里显示的输出:

<message type="warning" from="Dcd_Mux" timestamp="Mon Dec  1 02:31:18 2014"> Could not connect to Dcd </message>

我需要如何开始打开XML,通过整个事情循环,并删除具有符合我的筛选器属性的任何节点的一些方向。 我感兴趣的是使用的libxml来完成这件事。

Answer 1:

我使用XML ::的libxml作为我的XML解析器。

use XML::LibXML qw( );

die "usage\n" if @ARGV != 2;

my ($type, $qfn) = @ARGV;
my $doc = XML::LibXML->new->parse_file($qfn);
for my $node ($doc->findnodes('//message') {
   my $type_addr = $node->getAttribute('type');
   next if !$type_addr || $type_addr ne $type;

   $node->parentNode->removeChild($node);
}

$doc->toFile($qfn);


Answer 2:

它可能看起来像这样使用XML::LibXML

use strict;
use warnings; 

use XML::LibXML;

my $filename = $ARGV[0] 
   or die "Missing XML filename to parse";
my $type = $ARGV[1] 
   or die "Missing type of node to exclude";

open(my $xml_file, '<', $filename) 
   or die "Cannot open XML file '$filename' for reading: $!";

my $dom = XML::LibXML->load_xml(IO => $xml_file);
NODE:
foreach my $message_node ( $dom->findnodes('/root/message') ) {
   next NODE 
      unless $message_node->hasAttribute('type');

   $message_node->unbindNode() 
      if $message_node->getAttribute('type') eq $type;
}
$dom->toFile($filename);


Answer 3:

有两个元素,您的问题 - 先建立一个过滤条件,并在此基础上选择或删除元素。

特别 - 混合“添加”和“删除”可以说是相当困难的,因为决定做什么,如果他们不适用或矛盾可能相当烦人。

总之,我提供XML::Twig ,因为我已经使用了一个公平一点,并没有真正触动的libxml -尽管不是正是你问过什么。

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

use XML::Twig;

#read these from ARGV, just here as example.
my @sample_filters = qw ( -type=error
                          -from=Not_Dcd_Mux );

my %exclude;
for (@sample_filters) {
    if (m/^-/) {
        my ( $att, $criteria ) = (
            m/^-     #starts with -
              (\w+)  #word
              =     
              (\w+)
              $      #end of string
              /x
        );
        next unless $att;
        $exclude{$att} = $criteria;
    }
}

#process_message is called for each 'message' element, and tests filters for exclusion.
sub process_message {
    my ( $twig, $message ) = @_;
    foreach my $att ( keys %exclude ) {
        if ( $message->att($att) eq $exclude{$att} ) {
            $message->delete();
            last;
        }
    }
}

my $twig = XML::Twig->new(
    pretty_print  => 'indented',
    twig_handlers => { 'message' => \&process_message }
);
$twig->parse( \*DATA ); #might use 'parsefile ( $filename )' or 'STDIN' instead
$twig->print;


__DATA__
<XML>
<message type="error" from="Realtime" timestamp="Mon Nov 24 19:28:55 2014"> Could not receive from Loader </message>
<message type="warning" from="Not_Dcd_Mux" timestamp="Mon Dec  1 02:31:18 2014"> Could not connect to Dcd </message>
<message type="warning" from="Dcd_Mux" timestamp="Mon Dec  1 02:31:18 2014"> Could not connect to Dcd </message>
</XML>


Answer 4:

该解决方案是从猎人麦克迈林的一个变化,并且在这里主要是为了说明我的意思是“看起来像Perl编写的Java程序”。

参数验证是它的一部分,而我把它简化为简单的计数检查,通常我不会写的所有东西。 这是值得怀疑的因为这个问题是关于如何处理数据,任何这样的装饰品取决于谁将会使用计划和频率。

我所选择序列化输出并将其打印到STDOUT ,因为它往往是要能够在命令行上根据需要重定向输出更加有用。

我承认我的想法是通过注意验证和一般的Java风格的方法“保护我快乐”。 我不相信,添加标签,并在使用它next在所有有帮助的,尤其是这么短的循环。

use strict;
use warnings; 

use XML::LibXML::PrettyPrint;

@ARGV == 2 or die <<END_USAGE;
Usage:
  $0 <XML file> <node type>
END_USAGE

my ($xml_file, $exclude_type) = @ARGV;

my $dom = XML::LibXML->load_xml(location => $xml_file);

for my $node ( $dom->findnodes('/root/message[@type]') ) {
  my $type = $node->getAttribute('type');
  $node->unbindNode if $type eq $exclude_type;
}

local $XML::LibXML::skipXMLDeclaration = 1;
my $pp = XML::LibXML::PrettyPrint->new;
print $pp->pretty_print($dom)->toString;

产量

<root>
  <message type="warning" from="Dcd_Mux" timestamp="Mon Dec  1 02:31:18 2014">
    Could not connect to Dcd
  </message>
</root>


文章来源: How to filter out nodes from an XML using PERL script