| XML-Filter-SAXT documentation | Contained in the XML-Filter-SAXT distribution. |
XML::Filter::SAXT - Replicates SAX events to several SAX event handlers
$saxt = new XML::Filter::SAXT ( { Handler => $out1 },
{ DocumentHandler => $out2 },
{ DTDHandler => $out3,
Handler => $out4
}
);
$perlsax = new XML::Parser::PerlSAX ( Handler => $saxt );
$perlsax->parse ( [OPTIONS] );
SAXT is like the Unix 'tee' command in that it multiplexes the input stream to several output streams. In this case, the input stream is a PerlSAX event producer (like XML::Parser::PerlSAX) and the output streams are PerlSAX handlers or filters.
The SAXT constructor takes a list of hash references. Each hash specifies an output handler. The hash keys can be: DocumentHandler, DTDHandler, EntityResolver or Handler, where Handler is a combination of the previous three and acts as the default handler. E.g. if DocumentHandler is not specified, it will try to use Handler.
In this example we use XML::Parser::PerlSAX to parse an XML file and to invoke the PerlSAX callbacks of our SAXT object. The SAXT object then forwards the callbacks to XML::Checker, which will 'die' if it encounters an error, and to XML::Handler::BuildDOM, which will store the XML in an XML::DOM::Document.
use XML::Parser::PerlSAX;
use XML::Filter::SAXT;
use XML::Handler::BuildDOM;
use XML::Checker;
my $checker = new XML::Checker;
my $builder = new XML::Handler::BuildDOM (KeepCDATA => 1);
my $tee = new XML::Filter::SAXT ( { Handler => $checker },
{ Handler => $builder } );
my $parser = new XML::Parser::PerlSAX (Handler => $tee);
eval
{
# This is how you set the error handler for XML::Checker
local $XML::Checker::FAIL = \&my_fail;
my $dom_document = $parser->parsefile ("file.xml");
... your code here ...
};
if ($@)
{
# Either XML::Parser::PerlSAX threw an exception (bad XML)
# or XML::Checker found an error and my_fail died.
... your error handling code here ...
}
# XML::Checker error handler
sub my_fail
{
my $code = shift;
die XML::Checker::error_string ($code, @_)
if $code < 200; # warnings and info messages are >= 200
}
This is still alpha software. Package names and interfaces are subject to change.
Enno Dersken is the original author.
Send bug reports, hints, tips, suggestions to T.J. Mather at <tjmather@tjmather.com>.
| XML-Filter-SAXT documentation | Contained in the XML-Filter-SAXT distribution. |
# # To do: # - later: ErrorHandler, Locale? package XML::Filter::SAXT; use strict; use vars qw( $VERSION %SAX_HANDLERS ); $VERSION = 0.01; %SAX_HANDLERS = ( DocumentHandler => [ "start_document", "end_document", "start_element", "end_element", "characters", "processing_instruction", "comment", "start_cdata", "end_cdata", "entity_reference", "set_document_locator" # !! passes {Locator=>$perlsax} ], DTDHandler => [ "notation_decl", "unparsed_entity_decl", "entity_decl", "element_decl", "attlist_decl", "doctype_decl", "xml_decl" ], EntityResolver => [ "resolve_entity" ]); # # Usage: # # $saxt = new XML::Filter::SAXT ( { Handler => $out0 }, # { DocumentHandler => $out1 }, # { DTDHandler => $out3, # Handler => $out4 # } # ); # # $perlsax = new XML::Parser::PerlSAX ( Handler => $saxt ); # $perlsax->parse ( [OPTIONS] ); # sub new { my ($class, @out) = @_; my $self = bless { Out => \@out }, $class; for (my $i = 0; $i < @out; $i++) { for my $handler (keys %SAX_HANDLERS) { my $callbacks = $SAX_HANDLERS{$handler}; my $h = ($self->{Out}->[$i]->{$handler} ||= $self->{Out}->[$i]->{Handler}); next unless defined $h; for my $cb (@$callbacks) { if (UNIVERSAL::can ($h, $cb)) { $self->{$cb} .= "\$out->[$i]->{$handler}->$cb (\@_);\n"; } } } } for my $handler (keys %SAX_HANDLERS) { my $callbacks = $SAX_HANDLERS{$handler}; for my $cb (@$callbacks) { my $code = $self->{$cb}; if (defined $code) { $self->{$cb} = eval "sub { my \$out = shift->{Out}; $code }"; } else { $self->{$cb} = \&noop; } } } return $self; } sub noop { # does nothing } for my $cb (map { @{ $_ } } values %SAX_HANDLERS) { eval "sub $cb { shift->{$cb}->(\@_); }"; } 1; # package return code __END__