The "seek" function only works on disk files (no matter what programming language you're using), and cannot work on pipes.
If you need to make a routing decision after reading several lines from a pipe, you'll need to hold everything you read in a scalar or array until you are able to make your decision, and then send the accumulated stuff, along with whatever follows, to the appropriate recipient.
Update: So for example, something like:
my @holdem;
my %dispatch = ( one => \&subone, two => \&subtwo );
my $target;
open( $pipe, "-|", "ls" );
while ( <$pipe> ) {
if ( $target ) {
$target->( $_ );
}
else {
push @holdem, $_;
my $decision = look_for_evidence( $_ );
if ( $decision =~ /one|two/ ) {
$target = $dispatch{$decision};
$target->( $_ ) for ( @holdem );
}
}
}
(not tested) | [reply] [d/l] |
Thanks graff
I'm not sure I follow your suggestion fully though. As I said, I'm trying to pre-check some XML before I let XML::Parser do its magic.
my $parser = XML::Parser->new(
Handlers => {
Start => \&s_start,
End => \&s_end,
Final => \&s_final,
}
);
my %device_info = $parser->parse($fh);
It's the call to parse with a parameter of $fh that I'm not sure how to change. I need to peek inside $fh beforehand and set up different parser handler routines, depending on what I see. If I sneak a look before calling the parser, the first few lines of XML are lost and it dies with a malformed error, which is fair enough.
So, I need to remember the first 5 or so lines (no problem) and then somehow insert these in the front of the file that parse is going to read? But I don't understand how ...
Thanks | [reply] [d/l] [select] |
Ah -- sorry, I didn't catch the issue about passing the pipe file handle to XML::Parser.
If the idea of using IO::Unread doesn't work out (though I expect it will do fine), there's also the possibility that you can use a script like the one I suggested, but instead of having two different subs in the dispatch table, you would have two different command lines -- one being your (separate) XML parser script invoked in a way to handle one type of stream, and the other(s) for handling the other type(s) of stream, and you just launch the right one as a subprocess:
my @holdem;
my %dispatch = (
one => [ qw/my_parser --this_way/ ],
two => [ qw/my_parser --that_way/ ],
);
my $target;
open( $pipe, "-|", "some_xml_generator" ); # not "ls", obviously
while ( <$pipe> ) {
if ( $target ) {
print $target $_;
}
else {
push @holdem, $_;
my $decision = look_for_evidence( $_ );
if ( $decision =~ /one|two/ ) {
open( $target, "|-", @{$dispatch{$decision}} )
or die "failed to launch: $dispatch{$decision}: $!\n";
print $target $_ for ( @holdem );
}
}
}
Your separate parser script uses the command line option to control how to set up event handlers for parsing.
(updated snippet to fix stupid mistakes, like forgetting to use a list for "command", "option" when opening the pipe to the parser script.) | [reply] [d/l] |