XML-Generator-RSS10

 view release on metacpan or  search on metacpan

lib/XML/Generator/RSS10.pm  view on Meta::CPAN

        %p,
        state   => {},
        modules => \%mod,
    };

    $self->{state}{indent} = 0;
    $self->{state}{items}  = [];

    $self->_start;

    return $self;
}

sub parse {
    die __PACKAGE__ . " does not implement RSS parsing\n";
}

sub _start {
    my $self = shift;

    $self->start_document;

    $self->processing_instruction(
        { Target => 'xml', Data => 'version="1.0"' } );

    $self->_declare_namespaces;
    $self->_newline_if_pretty;

    $self->_start_element( 'rdf', 'RDF' );
    $self->_newline_if_pretty;
}

use constant ITEM_SPEC => (
    title       => { type => SCALAR },
    link        => { type => SCALAR },
    description => { type => SCALAR, optional => 1 },
);

sub item {
    my $self = shift;
    my %p    = validate(
        @_,
        {
            ITEM_SPEC,
            map { $_ => { optional => 1 } }
                keys %{ $self->{namespace_prefixes} },
        },
    );

    $self->_start_element(
        '', 'item',
        [ 'rdf', 'about' => $p{link} ],
    );
    $self->_newline_if_pretty;

    $self->_contents( \%p, qw( title link ) );

    $self->_call_modules( \%p );

    if ( defined $p{description} ) {
        $self->_element_with_cdata( '', 'description', $p{description} );
        $self->_newline_if_pretty;
    }

    $self->_end_element( '', 'item' );
    $self->_newline_if_pretty;

    push @{ $self->{state}{items} }, $p{link};

}

use constant IMAGE_SPEC => (
    title => { type => SCALAR },
    link  => { type => SCALAR },
    url   => { type => SCALAR },
);

sub image {
    my $self = shift;
    my %p    = validate(
        @_,
        {
            IMAGE_SPEC,
            map { $_ => { optional => 1 } }
                keys %{ $self->{namespace_prefixes} },
        },
    );

    die "Cannot call image() more than once.\n"
        if $self->{state}{image};

    die "Cannot call image() after calling channel().\n"
        if $self->{state}{finished};

    $self->_start_element(
        '', 'image',
        [ 'rdf', 'about' => $p{url} ],
    );
    $self->_newline_if_pretty;

    $self->_contents( \%p, qw( title url link ) );

    $self->_call_modules( \%p );

    $self->{state}{image} = $p{url};

    $self->_end_element( '', 'image' );
    $self->_newline_if_pretty;
}

use constant TEXTINPUT_SPEC => (
    title       => { type => SCALAR },
    description => { type => SCALAR },
    name        => { type => SCALAR },
    url         => { type => SCALAR },
);

sub textinput {
    my $self = shift;
    my %p    = validate(
        @_,
        {
            TEXTINPUT_SPEC,
            map { $_ => { optional => 1 } }
                keys %{ $self->{namespace_prefixes} },
        },
    );

    die "Cannot call textinput() more than once().\n"
        if $self->{state}{textinput};

    die "Cannot call textinput() after calling channel().\n"
        if $self->{state}{finished};

    $self->_start_element(
        '', 'textinput',
        [ 'rdf', 'about' => $p{url} ],
    );
    $self->_newline_if_pretty;

    $self->_contents( \%p, qw( title description name url ) );

    $self->_call_modules( \%p );

    $self->{state}{textinput} = $p{url};

    $self->_end_element( '', 'textinput' );
    $self->_newline_if_pretty;
}

use constant CHANNEL_SPEC => (
    title       => { type => SCALAR },
    link        => { type => SCALAR },
    description => { type => SCALAR },
);

sub channel {
    my $self = shift;
    my %p    = validate(
        @_,
        {
            CHANNEL_SPEC,
            map { $_ => { optional => 1 } }
                keys %{ $self->{namespace_prefixes} },
        },
    );

    die "Cannot call channel() without any items.\n"
        unless @{ $self->{state}{items} };

    die "Cannot call channel() more than once.\n"
        if $self->{state}{finished};

    $self->_start_element(
        '', 'channel',
        [ 'rdf', 'about' => $p{link} ],
    );
    $self->_newline_if_pretty;

    $self->_contents( \%p, qw( title link ) );

    $self->_element_with_cdata( '', 'description', $p{description} );
    $self->_newline_if_pretty;

    foreach my $elt ( grep { $self->{state}{$_} } qw( image textinput ) ) {
        $self->_element(
            '', $elt,
            [ 'rdf', 'resource' => $self->{state}{$elt} ],
        );
        $self->_newline_if_pretty;
    }

    $self->_start_element( '', 'items' );
    $self->_newline_if_pretty;

    $self->_start_element( 'rdf', 'Seq' );
    $self->_newline_if_pretty;

    foreach my $i ( @{ $self->{state}{items} } ) {
        $self->_element(
            'rdf', 'li',
            [ 'rdf', 'resource' => $i ],
        );
        $self->_newline_if_pretty;
    }

    $self->_end_element( 'rdf', 'Seq' );
    $self->_newline_if_pretty;

    $self->_end_element( '', 'items' );
    $self->_newline_if_pretty;

    $self->_call_modules( \%p );

    foreach my $mod ( values %{ $self->{modules} } ) {
        $mod->channel_hook($self) if $mod->can('channel_hook');
    }

    $self->_end_element( '', 'channel' );
    $self->_newline_if_pretty;

    $self->_finish;

    $self->{state}{finished} = 1;
}

sub _finish {
    my $self = shift;

    $self->_end_element( 'rdf', 'RDF' );
    $self->_newline_if_pretty;

    $self->end_document;
}

sub _contents {
    my $self     = shift;
    my $p        = shift;
    my @required = @_;

    for my $elt (@required) {
        $self->_element_with_data( '', $elt, $p->{$elt} );
        $self->_newline_if_pretty;
    }
}

sub _call_modules {
    my $self = shift;
    my $p    = shift;

    foreach my $pre ( sort keys %{ $self->{modules} } ) {
        next unless exists $p->{$pre};

        $self->{modules}{$pre}->contents( $self, $p->{$pre} );
    }
}

sub _element {
    my $self = shift;

    $self->_start_element(@_);
    $self->_end_element(@_);
}

sub _element_with_data {
    my $self = shift;
    my $data = pop;

    $self->_start_element(@_);
    $self->characters( { Data => $data } ) if length $data;
    $self->_end_element(@_);
}

sub _element_with_cdata {
    my $self = shift;
    my $data = pop;

    $self->_start_element(@_);
    if ( length $data ) {
        $self->start_cdata;
        $self->characters( { Data => $data } );
        $self->end_cdata;
    }
    $self->_end_element(@_);
}

sub _start_element {
    my $self = shift;
    my ( $name, $prefix ) = ( shift, shift );

    my %att;
    foreach my $a ( grep { @$_ } @_ ) {
        my ( $k, $v ) = $self->_rss_att(@$a);

        $att{$k} = $v;
    }

    $self->ignorable_whitespace( { Data => ' ' x $self->{state}{indent} } )
        if $self->{pretty} && $self->{state}{indent};

    $self->start_element(
        {
            $self->_rss_name_and_prefix( $name, $prefix ),
            Attributes => \%att,
        }
    );

    $self->{state}{indent}++;
}

sub _end_element {
    my $self = shift;

    if ( $self->{pretty} ) {
        unless ( ( caller(1) )[3] =~ /(?:_element|_element_with_c?data)$/ ) {
            $self->ignorable_whitespace(
                { Data => ' ' x ( $self->{state}{indent} - 1 ) } )
                if $self->{state}{indent} > 1;
        }
    }

    $self->end_element( { $self->_rss_name_and_prefix(@_) } );

    $self->{state}{indent}--;
}

sub _newline_if_pretty {
    $_[0]->ignorable_whitespace( { Data => "\n" } ) if $_[0]->{pretty};
}

{
    my %ns = (
        ''  => 'http://purl.org/rss/1.0/',
        rdf => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
    );

    sub _declare_namespaces {
        my $self = shift;

        while ( my ( $p, $uri ) = each %ns ) {
            $self->SUPER::start_prefix_mapping(
                { Prefix => $p, NamespaceURI => $uri } );



( run in 1.057 second using v1.01-cache-2.11-cpan-995e09ba956 )