Search code examples
perlxml-twig

How to apply an IN clause in Perl by passing arguments from the command line


I am new to Perl, and am trying to apply a filter condition on XML files using the XML::Twig module.

Following is my code:

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

use XML::Twig;

my $SOURCEFILE     = $ARGV[0];
my $FILELOCATIONIN = $ARGV[1];

my $twig = new XML::Twig( twig_handlers => { 'STOCKEXT/STOCK' => \&STOCK } );

$twig->parsefile($FILELOCATIONIN.'/'.$SOURCEFILE.'.xml');

$twig->set_pretty_print('indented');

$twig->print_to_file($FILELOCATIONIN.'/'.$SOURCEFILE.'out.xml');

sub TRADE {
    my ( $twig, $STOCK ) = @_;
    foreach  my $c ($STOCK)
        {
         $c->delete($STOCK)
         unless
         $c->att('origin') eq "HIGH_TRADE"

      ;
    }
}

Following is my XML :

<STOCKEXT>
  <STOCK origin = "HIGH_TRADE"/>
  <STOCK origin = "HIGH_TRADE"/>
  <STOCK origin = "HIGH_TRADE"/>
  <STOCK origin = "LOW_TRADE"/>
  <STOCK origin = "LOW_TRADE"/>
  <STOCK origin = "AVERAGE_TRADE"/>
</STOCKEXT>

Filtered Output XML:

<STOCKEXT>
  <STOCK origin = "HIGH_TRADE"/>
  <STOCK origin = "HIGH_TRADE"/>
  <STOCK origin = "HIGH_TRADE"/>
</STOCKEXT>

Now I am stuck, as I want to pass comma-separated argument in the command line so that HIGH_TRADE as well as AVERAGE_TRADE become legitimate STOCK.

As can be seen, in my current code, I pass two arguments. But I want to pass three arguments, third should be the filter condition in comma-separated format.

Hence, I am expecting my code to be invoked as

perl stock_filter.pl file_name.xml /opt/XML HIGH_TRADE,AVERAGE_TRADE

The third argument will be split and checked against the origin attribute of each STOCK element to declare it as legitimate.

This will help in future to change the filter conditions. Any addition or subtraction of filter condition will not change the code.


Solution

  • One way to do this is to store the values that you want to keep in a hash.

    Create the hash at the top of the script:

    my @origins_to_keep= split /,/, $ARGV[2];
    my %keep= map { $_ => 1 } @origins_to_keep;
    

    Use it in the handler:

    $c->delete($STOCK) unless $keep{$c->att('origin')}