package XML::Atom::Stream; use strict; use vars qw($VERSION); $VERSION = '0.02'; use Carp; use LWP::UserAgent; use XML::SAX::ParserFactory; use HTTP::Request; sub new { my($class, %param) = @_; my $self = bless \%param, $class; $self->init(); $self; } sub init { my $self = shift; $self->{ua} ||= LWP::UserAgent->new(agent => "XML::Atom::Stream/$VERSION"); $self->{callback} or Carp::croak("no callback specified."); $self->{parser} = $self->_setup_parser; } sub _setup_parser { my $self = shift; my $handler = XML::Atom::Stream::SAXHandler->new; $handler->{callback} = $self->{callback}; my $parser = XML::SAX::ParserFactory->parser( Handler => $handler ); return $parser; } sub connect { my($self, $url) = @_; $url or Carp::croak("URL needed for connect()"); $self->{ua}->get($url, ':content_cb' => sub { $self->on_content_cb(@_) }); } sub on_content_cb { my($self, $data, $res, $proto) = @_; $self->{parser}->parse_string($data); } package XML::Atom::Stream::SAXHandler; use XML::Atom::Feed; use XML::Handler::Trees; use base qw( XML::Handler::Tree ); sub end_element { my $self = shift; $self->SUPER::end_element(@_); my($ref) = @_; if ($ref->{LocalName} eq 'feed') { my $element = $self->{Curlist}; my $xml = qq(\n); my $dumper; $dumper = sub { my($ref) = @_; my($elem, $stuff) = splice @$ref, 0, 2; if ($elem eq '0') { $xml .= encode_xml($stuff); } elsif ($elem =~ /^\{(.*?)\}(\w+)$/) { my($xmlns, $tag) = ($1, $2); my $attr = shift @$stuff; $xml .= qq(<$tag); $xml .= ' ' . join(' ', map qq($_=") . encode_xml($attr->{$_}) . qq("), keys %$attr) if keys %$attr; $xml .= qq( xmlns="$xmlns") if $xmlns ne 'http://www.w3.org/2005/Atom'; if (@$stuff) { $xml .= ">"; $dumper->($stuff); $xml .= ""; } else { $xml .= "/>"; } } $dumper->($ref) if @$ref; }; $dumper->($element); my $feed = XML::Atom::Feed->new(Stream => \$xml); eval { $self->{callback}->($feed) }; Carp::carp $@ if $@; } } my %Map = ('&' => '&', '"' => '"', '<' => '<', '>' => '>', '\'' => '''); my $RE = join '|', keys %Map; sub encode_xml { my($str, $no_cdata) = @_; if (!$no_cdata && $str =~ m/ <[^>]+> ## HTML markup | ## or &(?:(?!(\#([0-9]+)|\#x([0-9a-fA-F]+))).*?); ## something that looks like an HTML entity. /x) { ## If ]]> exists in the string, encode the > to >. $str =~ s/]]>/]]>/g; $str = ''; } else { $str =~ s!($RE)!$Map{$1}!g; } $str; } 1; __END__ =head1 NAME XML::Atom::Stream - A client interface for AtomStream =head1 SYNOPSIS use XML::Atom::Stream; my $url = "http://danga.com:8081/atom-stream.xml"; my $client = XML::Atom::Stream->new( callback => \&callback, ); $client->connect($url); sub callback { my($atom) = @_; # $atom is a XML::Atom::Feed object } =head1 DESCRIPTION XML::Atom::Stream is a consumer of AtomStream. =head1 AUTHOR Tatsuhiko Miyagawa Emiyagawa@bulknews.netE with tips from Benjamin Trott and Brad Fitzpatrick. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L, L, http://www.livejournal.com/users/brad/2143713.html =cut