/usr/bin/stag-grep is in libdata-stag-perl 0.14-2.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | #!/usr/bin/perl -w
# POD docs at bottom of file
use strict;
use Carp;
use Data::Stag qw(:all);
use Getopt::Long;
my $fmt = "";
my $out = "";
my $mapf;
my $tosql;
my $toxml;
my $toperl;
my $debug;
my $help;
my $count;
my $ff;
my @queryl = ();
GetOptions(
"help|h"=>\$help,
"parser|format|p=s" => \$fmt,
"handler|writer|w=s" => \$out,
"count|c" => \$count,
"xml"=>\$toxml,
"perl"=>\$toperl,
"debug"=>\$debug,
"filterfile|f=s"=>\$ff,
"query|q=s@"=>\@queryl,
);
if ($help) {
system("perldoc $0");
exit 0;
}
my $w = shift;
my $sub;
if ($ff) {
$sub = do $ff;
if ($@) {
die $@;
}
}
elsif (@queryl) {
my $ev =
'sub { my $s=shift; '.
join(' && ',
map {
if (
/([\w\/]+)\s*(==|<=|>=|<|>|=)\s*(.*)/ || # op
/([\w\/]+)\s+(\S\S)\s+(.*)/ # lt,gt,etc
) {
my ($var, $op, $val) = ($1, $2, $3);
if ($op eq '=') {
if ($val =~ /^\d+$/ ||
$val =~ /^\d*\.\d+/) {
$op = '==';
}
else {
$op = 'eq';
$val = "'$val'";
}
}
"defined \$s->get('$var') && \$s->get('$var') $op $val"
}
else {
die($_);
}
} @queryl).
'}';
$sub = eval $ev;
if ($@) {
die $@;
}
}
else {
$sub = shift;
$sub = eval $sub;
}
if ($@) {
print $@;
exit 1;
}
my $c = 0;
my @files = @ARGV;
foreach my $fn (@files) {
my $handler = Data::Stag->makehandler($w=>sub {
my $self = shift;
my $stag = shift;
my $ok = $sub->($stag);
if ($ok) {
$c++;
return $stag;
}
else {
$stag->free;
return;
}
});
if ($count) {
$out = 'Data::Stag::null';
}
if (!$out) {
$out = 'xml';
}
my $ch = Data::Stag->chainhandlers($w, $handler, $out);
my @pargs = (-file=>$fn, -format=>$fmt, -handler=>$ch);
if ($fn eq '-') {
if (!$fmt) {
$fmt = 'xml';
}
@pargs = (-format=>$fmt, -handler=>$ch, -fh=>\*STDIN);
}
my $tree =
Data::Stag->parse(@pargs);
if ($count) {
print "$c\n";
}
# my @res =
# $tree->where($w,
# $sub);
# print $_->xml foreach @res;
}
exit 0;
__END__
=head1 NAME
stag-grep - filters a stag file (xml, itext, sxpr) for nodes of interest
=head1 SYNOPSIS
stag-grep person -q name=fred file1.xml
stag-grep person 'sub {shift->get_name =~ /^A*/}' file1.xml
stag-grep -p My::Foo -w sxpr record 'sub{..}' file2
=head1 USAGE
stag-grep [-p|parser PARSER] [-w|writer WRITER] NODE -q tag=val FILE
stag-grep [-p|parser PARSER] [-w|writer WRITER] NODE SUB FILE
stag-grep [-p|parser PARSER] [-w|writer WRITER] NODE -f PERLFILE FILE
=head1 DESCRIPTION
parsers an input file using the specified parser (which may be a built
in stag parser, such as xml) and filters the resulting stag tree
according to a user-supplied subroutine, writing out only the
nodes/elements that pass the test.
the parser is event based, so it should be able to handle large files
(although if the node you parse is large, it will take up more memory)
=head1 ARGUMENTS
=over
=item -p|parser FORMAT
FORMAT is one of xml, sxpr or itext, or the name of a perl module
xml assumed as default
=item -w|writer FORMAT
FORMAT is one of xml, sxpr or itext, or the name of a perl module
=item -c|count
prints the number of nodes that pass the test
=item -filterfile|f
a file containing a perl subroutine (in place of the SUB argument)
=item -q|query TAG1=VAL1 -q|query TAG2=VAL2 ... -q|query TAGN=VALN
filters based on the field TAG
other operators can be used too - eg <, <=, etc
multiple q arguments can be passed in
for more complex operations, pass in your own subroutine, see below
=item SUB
a perl subroutine. this subroutine is evaluated evry time NODE is
encountered - the stag object for NODE is passed into the subroutine.
if the subroutine passes, the node will be passed to the writer for
display
=item NODE
the name of the node/element we are filtering on
=item FILE
the file to be parser. If no parser option is supplied, this is
assumed to a be a stag compatible syntax (xml, sxpr or itext);
otherwise you should parse in a parser name or a parser module that
throws stag events
=back
=head1 SEE ALSO
L<Data::Stag>
=cut
|