POE::XUL::RDF - RDF builder class


POE-XUL documentation Contained in the POE-XUL distribution.

Index


Code Index:

NAME

Top

POE::XUL::RDF - RDF builder class

SYNOPSIS

Top

    use POE::XUL::RDF;

    my $data = [
        'RDF:about' => "all-animals",
        { name => 'Lion', species => 'Panthera leo', class => 'Mammal',
            'RDF:about' => "mammals/lion" },
        { name => 'Tarantula', species => 'Avicularia avicularia',
                        class => 'Arachnid',
            'RDF:about' => "arachnids/tarantula" },
        { name => 'Hippopotamus', species => 'Hippopotamus amphibius',
                        class => 'Mammal',
            'RDF:about' => 'mammals/hippopotamus'
        }
    ];

    my $rdf = POE::XUL::RDF->new( baseref => "http://some-url.com" );
    $rdf->baserdf( 'rdf' );
    $rdf->data( $data );

    my $tree = Tree( datasources => $rdf, 
                     ref => $ref->dataref
                     # ...
                   );




DESCRIPTION

Top

Primitive RDF generation for XUL trees.

METHODS

Top

new

    my $rdf = POE::XUL::RDF->new( %params );

Creates a new object. %params may contain NS, baseref, baserdf, dataref or data.

NS

Namespace of the XML tags your data tuples will live in.

baseref

    $rdf->baseref( $url );
    $url = $rdf->baseref;

Get or set the base URL used to create baserdf, dataref and about.

baserdf

    $rdf->baserdf( $url );
    $url = $rdf->baserdf;

Get or set the base URL of the data. Defaults to 'rdf' under baseref.

dataref

    $rdf->baserdf( $url );
    $tree->setAttribute( ref => $rdf->dataref );

Get or set the URL of the main data sequence. Can also be set if you have an RDF:about in your data.

data

    $rdf->data( $AoH );
    $AoH = $rdf->data;

Get or set the data contained in the RDF. POE::XUL::RDF only implements a simplified data format. $AoH must be an arrayref of hashrefs. The top arrayref is a RDF:Seq. Each hashref is an RDF:li. Keys are the XML tags in the NS namespace. Values are text nodes. If a key name begins with 'RDF:' it is placed as an attribute of the RDF:Description.

Example:

    [ { city=>"Montreal", TZ=>"+5", 'RDF:note' => 'Something' },
      { city=>"Cochabamba", TZ=>"+4" }
    ]

Becomes roughly

    <RDF:Seq>
        <RDF:li><RDF:Description note="Something">
            <NS:city>Montreal</NS:city> 
            <NS:TZ>+5</NS:TZ>
        </RDF:Description></RDF:li>
        <RDF:li><RDF:Description>
            <NS:city>Cochabamba</NS:city>
            <NS:TZ>+4</NS:TZ>
        </RDF:Description></RDF:li>
    </RDF:Seq>




RDF:about

RDF:about is a special attribute. Is is converted into an absolute URL with baseref.

What's more, if the first element in data is the string 'RDF:about', the second element is used as the about attribute of the main RDF:Seq.

Example:

    $rdf->baseref( 'http://example.com' );
    $rdf->data( [ 'RDF:about' => 'some-cities', 
                  { city=>"Montreal", TZ=>"+5", 'RDF:about' => 'canada/mtl' },
              ] );

Becomes roughly:

    <RDF:Seq about="http://example.com/some-cities>
        <RDF:li><RDF:Description about="http://example.com/canada/mtl>
            <NS:city>Montreal</NS:city> 
            <NS:TZ>+5</NS:TZ>
        </RDF:Description></RDF:li>
    </RDF:Seq>




fragment

    my $frag = $rdf->fragment( $name );

Builds an URL that references $name fragment of the current RDF.

rdf_fragment

    my $frag = $rdf->rdf_fragment( $name );

Builds an rdf: URL that references $name fragment of the current RDF. Useful for setting the sort attribute of a TreeCol, for example

        TreeCol( id=>'TZ', sort=>$rdf->rdf_fragment( 'TZ' ) );




DATASOURCES INTERFACE

Top

The following 3 methods are used to interface with the ChangeManager. You might want to overload them if you wish to define a new type of datasource. For example, a DBI datasource.

as_xml

    my $xml = $rdf->as_xml;

Convert the RDF to an XML string.

mime_type

    $resp->content_type( $rdf->mime_type );

Returns the MIME-type of the RDF. Defaults to 'application/rdf+xml'.

index_of

    my $row = $rdf->index_of( $col, $value );

Search the the first tupple that has the $col column set to $value. This is needed because if the user has sorted the data in the browser, the Select event's selectedIndex will reference the row as seen on the screen, not the row as present in the dataset.

SEE ALSO

Top

POE::XUL::Node

AUTHOR

Top

Philip Gwyn <gwyn-at-cpan.org>

COPYRIGHT AND LICENSE

Top


POE-XUL documentation Contained in the POE-XUL distribution.

package POE::XUL::RDF;
# $Id$
# Copyright Philip Gwyn 2008-2010.  All rights reserved.

use strict;
use warnings;

use URI;
use HTML::Entities qw( encode_entities_numeric );

our $VERSION = '0.0600';

##############################################################
sub new
{
    my( $package, %init ) = @_;
    my $self = bless { data=>[] }, $package;

    # XXX: baseref from current server 
    $self->baseref( $init{baseref} ) if $init{baseref};
    $init{baserdf} ||= 'rdf';
    $self->baserdf( $init{baserdf} ) if $init{baserdf};
    $self->NS( $init{NS} )           if $init{NS};
    $self->data( $init{data} )       if $init{data};
    if( exists $init{dataref} ) {
        $self->dataref( $init{dataref} );
    }
    elsif( ($self->{data}[0]||'') eq 'RDF:about' ) {
        $self->dataref( $self->{data}[1] );
    }

    return $self;
}

##############################################################
sub fragment
{
    my( $self, $name ) = @_;
    my $ret = URI->new( $self->{baserdf} );
    $ret->fragment( $name );
    return $ret;
}

sub rdf_fragment
{
    my( $self, $name ) = @_;
    my $ret = $self->fragment( $name );
    return "rdf:$ret";
}

##############################################################
sub data
{
    my( $self, $data ) = @_;
    return $self->{data} if 1==@_;
    $self->{data} = $data;
}

sub NS
{
    my( $self, $NS ) = @_;
    return $self->{NS} if 1==@_;
    $self->{NS} = $NS;
}

sub baseref
{
    my( $self, $baseref ) = @_;
    return $self->{baseref} if 1==@_;
    $self->{baseref} = URI->new( $baseref );
}

sub baserdf
{
    my( $self, $baserdf ) = @_;
    return $self->{baserdf} if 1==@_;
    if( $self->{baseref} ) {
        $self->{baserdf} = URI->new_abs( $baserdf, $self->{baseref} );
    }
    else {
        $self->{baserdf} = URI->new( $baserdf );
    }
    $self->{baserdf}->fragment( '' );
    return $self->{baserdf};        
}

sub dataref
{
    my( $self, $dataref ) = @_;
    return $self->{dataref} if 1==@_;
    if( $self->{baseref} ) {
        $self->{dataref} = URI->new_abs( $dataref, $self->{baseref} );
    }
    else {
        $self->{dataref} = URI->new( $dataref );
    }
    return $self->{dataref};
}


##############################################################
sub mime_type
{
    return 'application/rdf+xml';
}

##############################################################
## Linear search for the true row that was selected.
sub index_of
{
    my( $self, $col, $primary ) = @_;
    my $offset=0;
    for( my $q=0; $q <= $#{$self->{data}}; $q++ ) {
        if( not ref $self->{data}[$q] ) {
            $offset+=2;
            $q+=2;
        }
        next unless exists $self->{data}[$q]{$col} and
                           $self->{data}[$q]{$col} eq $primary;
        return $q-$offset;
    }
    return -1;
}

##############################################################
sub as_xml
{
    my( $self, $data ) = @_;

    $data ||= $self->{data};
    my @Seq = ( 'RDF:Seq', {}, [] );

    my @RDF = [ 'RDF:RDF', { 'xmlns:RDF' => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", 
                             "xmlns:$self->{NS}" => $self->{baserdf}
                           }, 
                [ \@Seq ]
              ];

    if( $data->[0] eq 'RDF:about' ) {
        $Seq[1]{about} = URI->new_abs( $data->[1], $self->{baseref} );
        $data = [ @{ $data }[ 2..$#$data ] ];
    }

    foreach my $row ( @$data ) {
        push @{ $Seq[2] }, [ 'RDF:li', {}, 
                                [[ 'RDF:Description', {}, [] ]]
                           ];
        my $li = $Seq[2][-1][2][0][2];
        my $att = $Seq[2][-1][2][0][1];
        while( my( $k, $v ) = each %$row ) {
            if( $k =~ /^RDF:(\w+)$/ ) {
                my $a = $1;
                if( $a eq 'about' ) {
                    $att->{$a} = URI->new_abs( $v, $self->{baseref} );
                }
                else {
                    $att->{$a} = $v;
                }
            }
            else {
                push @$li, [ "$self->{NS}:$k", {}, [ $v ] ];
            }
        }
    }
#    use Data::Dumper;
#    warn Dumper \@RDF;

    return $self->_rdf2xml( [@RDF], '' );
}

##############################################################
sub _rdf2xml
{
    my( $self, $rdf, $prefix ) = @_;

    my @ret;
    foreach my $el ( @$rdf ) {
        if( ref $el ) {
            push @ret, "$prefix<$el->[0]".$self->_att2xml( $el->[1] );
            if( $el->[2] and @{ $el->[2] } ) {
                $ret[-1] .= ">";
                if( ref $el->[2][0] ) {
                    push @ret, $self->_rdf2xml( $el->[2], "$prefix  " );
                    push @ret, "$prefix</$el->[0]>";
                }
                else {
                    $ret[-1] .= "$el->[2][0]</$el->[0]>";
                }
            }
            else {
                $ret[-1] .= "/>";
            }
        }
        else {
            push @ret, $el;
        }
    }

    return join "\n", @ret;
}

sub _att2xml
{
    my( $self, $att ) = @_;
    return '' unless keys %$att;
    return join ' ', '', map { 
                join '', 
                    encode_entities_numeric( $_, "\x00-\x1f<>&\'\x80-\xff" ),
                    '="', 
                    encode_entities_numeric( $att->{$_}, "\x00-\x1f<>&\'\x80-\xff" ),
                    '"'
                } keys %$att;
}

1;

__END__