# $Id: /mirror/perl/XML-RSS-LibXML/trunk/lib/XML/RSS/LibXML/V0_9.pm 2259 2007-05-07T14:41:59.593216Z daisuke $ # # Copyright (c) 2005-2007 Daisuke Maki # All rights reserved. package XML::RSS::LibXML::V0_9; use strict; use base qw(XML::RSS::LibXML::ImplBase); use Carp qw(croak); use XML::RSS::LibXML::Namespaces qw(NS_RSS09 NS_RDF); my $format_dates = sub { my $v = eval { DateTime::Format::W3CDTF->format_datetime( DateTime::Format::Mail->parse_datetime($_[0]) ); }; if ($v && ! $@) { $_[0] = $v; } }; my %DcElements = ( 'dc:date' => { candidates => [ { module => 'dc', element => 'date' }, 'pubDate', 'lastBuildDate', ], callback => $format_dates }, (map { ("dc:$_" => [ { module => 'dc', element => $_ } ]) } qw(language rights publisher creator title subject description contributer type format identifier source relation coverage)), ); my %ImageElements = ( (map { ($_ => [$_]) } qw(title url link)), %DcElements, ); my %TextInputElements = ( (map { ($_ => [$_]) } qw(title link description name)), %DcElements ); sub definition { return { channel => { title => '', description => '', link => '', }, image => bless({ title => undef, url => undef, link => undef, }, 'XML::RSS::LibXML::ElementSpec'), textinput => bless({ title => undef, description => undef, name => undef, link => undef, }, 'XML::RSS::LibXML::ElementSpec'), }, } sub accessor_definition { return +{ channel => { "title" => [1, 40], "description" => [1, 500], "link" => [1, 500] }, image => { "title" => [1, 40], "url" => [1, 500], "link" => [1, 500] }, item => { "title" => [1, 100], "link" => [1, 500] }, textinput => { "title" => [1, 40], "description" => [1, 100], "name" => [1, 500], "link" => [1, 500] } } } sub parse_dom { my $self = shift; my $c = shift; my $dom = shift; $c->reset; $c->version(0.9); $self->parse_namespaces($c, $dom); $c->internal('prefix', 'rss09'); # Check if we have non-default RSS namespace my $namespaces = $c->namespaces; while (my($prefix, $uri) = each %$namespaces) { if ($uri eq NS_RSS09 && $prefix ne '#default') { $c->internal('prefix', $prefix); last; } } $dom->getDocumentElement()->setNamespace(NS_RSS09, $c->internal('prefix'), 0); $self->parse_channel($c, $dom); $self->parse_items($c, $dom); $self->parse_misc_simple($c, $dom); } sub parse_namespaces { my ($self, $c, $dom) = @_; $self->SUPER::parse_namespaces($c, $dom); my $namespaces = $c->namespaces; while (my($prefix, $uri) = each %$namespaces) { if ($uri eq NS_RSS09) { } } } sub parse_channel { my ($self, $c, $dom) = @_; my $xc = $c->create_xpath_context($c->{namespaces}); my ($root) = $xc->findnodes('/rdf:RDF/rss09:channel', $dom); my %h = $self->parse_children($c, $root); foreach my $field qw(textinput image) { delete $h{$field}; # if (my $v = $h{$field}) { # $c->$field(UNIVERSAL::isa($v, 'XML::RSS::LibXML::MagicElement') ? $v : %$v); # } } $c->channel(%h); } sub parse_items { my $self = shift; my $c = shift; my $dom = shift; my @items; my $version = $c->version; my $xc = $c->create_xpath_context($c->{namespaces}); my $xpath = '/rdf:RDF/rss09:item'; foreach my $item ($xc->findnodes($xpath, $dom)) { my $i = $self->parse_children($c, $item); $self->add_item($c, $i); } } sub parse_misc_simple { my ($self, $c, $dom) = @_; my $xc = $c->create_xpath_context($c->{namespaces}); foreach my $node ($xc->findnodes('/rdf:RDF/*[name() != "channel" and name() != "item"]', $dom)) { my $h = $self->parse_children($c, $node); my $name = $node->localname; $name = 'textinput' if $name eq 'textInput'; my $prefix = $node->getPrefix(); if ($prefix) { $c->{$prefix} ||= {}; $self->store_element($c->{$prefix}, $name, $h); # XML::RSS requires us to allow access to elements both from # the prefix and the namespace $c->{$c->{namespaces}{$prefix}} ||= {}; $self->store_element($c->{$c->{namespaces}{$prefix}}, $name, $h); } else { $self->store_element($c, $name, $h); } } } sub validate_item { my $self = shift; my $c = shift; my $h = shift; # make sure we have a title and link croak "title and link elements are required" unless (defined $h->{title} && defined $h->{'link'}); # check string lengths croak "title cannot exceed 100 characters in length" if (length($h->{title}) > 100); croak "link cannot exceed 500 characters in length" if (length($h->{'link'}) > 500); croak "description cannot exceed 500 characters in length" if (exists($h->{description}) && length($h->{description}) > 500); # make sure there aren't already 15 items croak "total items cannot exceed 15 " if (@{$c->items} >= 15); } sub create_dom { my ($self, $c) = @_; my $dom = $self->SUPER::create_dom($c); my $xc = $c->create_xpath_context($c->namespaces); my ($channel) = $xc->findnodes('/rdf:RDF/channel', $dom); my $root = $dom->getDocumentElement(); if (my $image = $c->image) { my $inode; $inode = $dom->createElement('image'); $inode->setAttribute('rdf:resource', $image->{url}) if defined $image->{url}; $channel->appendChild($inode); $inode = $dom->createElement('image'); $inode->setAttribute('rdf:resource', $image->{url}) if defined $image->{url}; $self->create_element_from_spec($image, $dom, $inode, \%ImageElements); $self->create_extra_modules($image, $dom, $inode, $c->namespaces); $root->appendChild($inode); } if (my $textinput = $c->textinput) { my $inode; $inode = $dom->createElement('textinput'); $inode->setAttribute('rdf:resource', $textinput->{link}) if $textinput->{link}; $channel->appendChild($inode); $inode = $dom->createElement('textinput'); $inode->setAttribute('rdf:resource', $textinput->{link}) if $textinput->{link}; $self->create_element_from_spec($textinput, $dom, $inode, \%TextInputElements); $self->create_extra_modules($textinput, $dom, $inode, $c->namespaces); $root->appendChild($inode); } return $dom; } sub create_rootelement { my $self = shift; my $c = shift; my $dom = shift; my $e = $dom->createElementNS(NS_RSS09, 'RDF'); $dom->setDocumentElement($e); $e->setNamespace(NS_RDF, 'rdf', 1); $c->add_module(prefix => 'rdf', uri => NS_RDF); } sub create_channel { my $self = shift; my $c = shift; my $dom = shift; my $root = $dom->getDocumentElement(); my $channel = $dom->createElement('channel'); $root->appendChild($channel); my $node; foreach my $p qw(title link description) { my $text = $c->{channel}{$p}; next unless defined $text; $node = $dom->createElement($p); $node->appendText($c->{channel}{$p}); $channel->appendChild($node); } } sub create_items { my $self = shift; my $c = shift; my $dom = shift; my $root = $dom->getDocumentElement(); foreach my $i ($c->items) { my $item = $self->create_item($c, $dom, $i); $root->appendChild($item); } } sub create_item { my $self = shift; my $c = shift; my $dom = shift; my $i = shift; my $item = $dom->createElement('item'); my $node; foreach my $e qw(title link) { $node = $dom->createElement($e); $node->appendText($i->{$e}); $item->addChild($node); } return $item; } 1;