#!/usr/bin/perl package XML::SAX::ExpatNB; use base qw/XML::SAX::Expat/; use strict; use warnings; use XML::Parser (); use Carp qw/croak/; sub _really_create_parser { my $p = shift; my $opt = shift; $p->{_xml_parser_obj} ||= $p->SUPER::_create_parser($opt); } sub _create_parser { my $p = shift; $p->_expat_obj; } sub _expat_obj { my $p = shift; $p->{_expat_nb_obj} = shift if @_; $p->{_expat_nb_obj}; } sub _parser_obj { my $p = shift; $p->{_xml_parser_obj} = shift if @_; $p->{_xml_parser_obj}; } sub parse { my $p = shift; my $opts = $p->get_options(@_); if ($p->{Parent}){ return $p->{Parent}->parse($opts); } else { if (defined $opts->{Source}{String}){ return $p->_parse_string($opts->{Source}{String}); } else { croak "The only thing I know how to parse is a string. You have to fetch me the data yourself."; } } } sub parse_more { my $p = shift; $p->parse_string(@_); } sub _parse_string { my $p = shift; my $xml = shift; $p->parse_start unless $p->{_parsing}; $p->_expat_obj->parse_more($xml); } sub parse_start { my $p = shift; my $opt = shift; croak "Can't parse_start - Already started" if $p->{_parsing}; $p->{_parsing} = 1; $p->_really_create_parser($opt); $p->_expat_obj($p->_parser_obj->parse_start); } sub parse_done { my $p = shift; croak "Can't parse_done - Havn't started parsing" unless $p->{_parsing}; undef $p->{_parsing}; $p->_expat_obj->parse_done; } __PACKAGE__ __END__ =pod =head1 NAME XML::SAX::ExpatNB - XML::SAX::Expat subclass for nonblocking parsing. =head1 SYNOPSIS use XML::SAX::ExpatNB; # don't do this, use XML::SAX::ParserFactory my $p = XML::SAX::ExpatNB->new( Handler => MyHandler->new ); $p->parse_start; while (){ $p->parse_more($_); # or $p->parse_string($_); } $p->parse_done; =head1 DESCRIPTION Most XML parsers give a callback interface within an encapsulated loop. That is, you call $p->parse_whatever($whatever); And eventually, when C<$whatever> is depleted by the parser, C<< $p->parse >> will return. Sometimes you don't want the parser to control the loop for you. For example, if you need to retrieve your XML in chunks in a funny way, you might need to do something like my $doc = ''; while (defined(my $buffer = get_more_xml())) { $doc .= $buffer; } $p->parse_string($doc); which is not very convenient, or efficient. You could use L to tie a filehandle which does this for you, but that only works some of the time (for example, say you have two inputs coming in simultaneously). L solves this by providing three methods: =over 4 =item parse_start =item parse_more =item parse_done =back This interface lets you move the loop to outside the parser, retaining control. The callbacks are executed in the same manner, just that now, when there is no left to parse, instead of taking more data from a source on it's own, the parser returns control to you. $p->parse_start; # you can omit this - parse_start will # be called automatically as needed while(defined(my $buffer = get_more_xml())) { $p->parse_more($buffer); } $p->parse_done; This module is a subclass of L which is to L as L is to L itself. =cut