# -*- Mode: Perl -*-
#
# Model.pm - Redland Perl RDF Model module
#
# Copyright (C) 2000-2005 David Beckett - http://www.dajobe.org/
# Copyright (C) 2000-2005 University of Bristol - http://www.bristol.ac.uk/
#
# This package is Free Software and part of Redland http://librdf.org/
#
# It is licensed under the following three licenses as alternatives:
# 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
# 2. GNU General Public License (GPL) V2 or any newer version
# 3. Apache License, V2.0 or any newer version
#
# You may not use this file except in compliance with at least one of
# the above three licenses.
#
# See LICENSE.html or LICENSE.txt at the top of this package for the
# full license terms.
#
#
#
package RDF::Redland::Model;
use strict;
use RDF::Redland::Iterator;
use RDF::Redland::Stream;
=pod
=head1 NAME
RDF::Redland::Model - Redland RDF Model Class
=head1 SYNOPSIS
use RDF::Redland;
my $storage=new RDF::Redland::Storage("hashes", "test", "new='yes',hash-type='memory'");
my $model=new RDF::Redland::Model($storage, "");
...
my(@sources)=$model->targets($predicate_node, $object_node);
...
=head1 DESCRIPTION
Manipulate the RDF model.
=cut
######################################################################
=pod
=head1 CONSTRUCTORS
=over
=item new STORAGE OPTIONS_STRING
=item new_with_options STORAGE OPTIONS_HASH
Create a new RDF::Redland::Model object using RDF::Redland::Storage object I<STORAGE>
with a options. The options can be given either as a string in
the first form as I<OPTIONS_STRING>. The options take the form
key1='value1',key2='value2'. The quotes are required. In the
second case I<OPTIONS_HASH> is a reference to a Perl hash of options.
=cut
sub new ($$$) {
my($proto,$storage,$options_string)=@_;
my $class = ref($proto) || $proto;
my $self = {};
warn qq{RDF::Redland::Model->new(storage, "$options_string")\n} if $RDF::Redland::Debug;
$self->{MODEL}=&RDF::Redland::CORE::librdf_new_model($RDF::Redland::World->{WORLD},$storage->{STORAGE},$options_string);
return undef if !$self->{MODEL};
# keep a reference to storage so model is always destroyed before storage
$self->{STORAGE}=$storage;
bless ($self, $class);
return $self;
}
sub new_with_options ($$$) {
my($proto,$storage,$options)=@_;
my $class = ref($proto) || $proto;
my $self = {};
my $options_hash=RDF::Redland::Hash->new_from_perl_hash($options);
$self->{MODEL}=&RDF::Redland::CORE::librdf_new_model_with_options($storage->{STORAGE},$options_hash->{HASH});
return undef if !$self->{MODEL};
# keep a reference to storage so model is always destroyed before storage
$self->{STORAGE}=$storage;
bless ($self, $class);
return $self;
}
=item new_from_model MODEL
Create a new model from an existing RDF::Redland::Model I<MODEL> (copy constructor).
=cut
sub new_from_model ($$) {
my($proto,$model)=@_;
my $class = ref($proto) || $proto;
my $self = {};
$self->{MODEL}=&RDF::Redland::CORE::librdf_new_model_from_model($model->{MODEL});
return undef if !$self->{MODEL};
bless ($self, $class);
return $self;
}
=pod
=back
=cut
# DESTRUCTOR
sub DESTROY ($) {
my $self=shift;
warn "RDF::Redland::Model DESTROY $self" if $RDF::Redland::Debug;
if(!$self->{MODEL}) {
warn "RDF::Redland::Model DESTROY - librdf model object gone\n" if $RDF::Redland::Debug;
} else {
&RDF::Redland::CORE::librdf_free_model($self->{MODEL});
}
warn "RDF::Redland::Model DESTROY done\n" if $RDF::Redland::Debug;
}
=head1 METHODS
=over
=item size
Return the size of the model (number of statements).
=cut
sub size ($) {
&RDF::Redland::CORE::librdf_model_size(shift->{MODEL});
}
=item sync
Synchronise the model to the underlying storage.
=cut
sub sync ($) {
&RDF::Redland::CORE::librdf_model_sync(shift->{MODEL});
}
=item add SUBJECT PREDICATE OBJECT
Add a new statement to the model with I<SUBJECT>,
I<PREDICATE> and I<OBJECT>. These can be
RDF::Redland::Node, RDF::Redland::URI or perl URI objects.
=cut
sub add ($$$$) {
my($self,$subject,$predicate,$object)=@_;
return $self->add_statement($subject,$predicate,$object);
}
=item add_typed_literal_statement SUBJECT PREDICATE STRING [XML_LANGUAGE [DATATYPE]]
Add a new statement to the model containing a typed literal string object
I<STRING> with (optional) XML language (xml:lang attribute) I<XML_LANGUAGE>
and (optional) datatype URI I<DATATYPE>. I<XML_LANGUAGE>
or I<DATATYPE> can either or both be set to undef.
=cut
sub add_typed_literal_statement ($$$$$;$$) {
my($self,$subject,$predicate,$string,$xml_language,$datatype)=@_;
$subject=&RDF::Redland::CORE::librdf_new_node_from_node($subject->{NODE});
$predicate=&RDF::Redland::CORE::librdf_new_node_from_node($predicate->{NODE});
$xml_language ||= "";
my $uri=$datatype ? $datatype->{URI} : undef;
return &RDF::Redland::CORE::librdf_model_add_typed_literal_statement($self->{MODEL},$subject,$predicate,$string,$xml_language,$uri);
}
=item add_statement STATEMENT [CONTEXT] | NODE NODE NODE [CONTEXT]
Add RDF::Redland::Statement I<STATEMENT>
or the statement formed by I<NODE NODE NODE> to the model.
If the optional I<CONTEXT> is given, associate it with that context.
Any of I<NODE> or I<CONTEXT> can be a RDF::Redland::Node,
RDF::Redland::URI or perl URI object.
=cut
sub add_statement ($;$$$$) {
my($self,@rest)=@_;
my $statement=undef;
if(scalar(@rest)>2) {
$statement=new RDF::Redland::Statement(splice(@rest, 0, 3));
} else {
$statement=shift(@rest);
}
my $node=shift(@rest);
if($node) {
my $class=ref($node);
$node=&RDF::Redland::Node::_ensure($node);
die "Cannot make a Node from an object of class $class\n"
unless $node;
return &RDF::Redland::CORE::librdf_model_context_add_statement($self->{MODEL},$node,$statement->{STATEMENT});
} else {
return &RDF::Redland::CORE::librdf_model_add_statement($self->{MODEL},$statement->{STATEMENT});
}
}
=item add_statements STREAM [CONTEXT]
Add the statements from the RDF::Redland::Stream I<STREAM> to the
model. If the optional I<CONTEXT> is given,
associate it with that context.
I<CONTEXT> can be a RDF::Redland::Node, RDF::Redland::URI or perl URI object.
=cut
sub add_statements ($$;$) {
my($self,$statement_stream,$node)=@_;
if($node) {
my $class=ref($node);
$node=&RDF::Redland::Node::_ensure($node);
die "Cannot make a Node from an object of class $class\n"
unless $node;
return &RDF::Redland::CORE::librdf_model_context_add_statements($self->{MODEL},$node,$statement_stream->{STREAM});
} else {
return &RDF::Redland::CORE::librdf_model_add_statements($self->{MODEL},$statement_stream->{STREAM});
}
}
=item remove_statement STATEMENT [CONTEXT] | NODE NODE NODE [CONTEXT]
Remove RDF::Redland::Statement I<STATEMENT>
or the statement formed by I<NODE NODE NODE> from the model.
If the optional I<CONTEXT> is given,
remove only the statement stored with that context.
Any of I<NODE> or I<CONTEXT> can be a RDF::Redland::Node,
RDF::Redland::URI or perl URI object.
=cut
sub remove_statement ($;$$$$) {
my($self,@rest)=@_;
my $statement=undef;
if(scalar(@rest)>2) {
$statement=new RDF::Redland::Statement(splice(@rest, 0, 3));
} else {
$statement=shift(@rest);
}
my $node=shift(@rest);
if($node) {
my $class=ref($node);
$node=&RDF::Redland::Node::_ensure($node);
die "Cannot make a Node from an object of class $class\n"
unless $node;
return &RDF::Redland::CORE::librdf_model_context_remove_statement($self->{MODEL},$node,$statement->{STATEMENT});
} else {
return &RDF::Redland::CORE::librdf_model_remove_statement($self->{MODEL},$statement->{STATEMENT});
}
}
=item remove_context_statements CONTEXT
Remove all RDF::Redland::Statement I<STATEMENT>s from the model
with the given I<CONTEXT> context.
I<CONTEXT> can be a RDF::Redland::Node, RDF::Redland::URI or perl URI object.
=cut
sub remove_context_statements ($$) {
my($self,$node)=@_;
my $class=ref($node);
$node=&RDF::Redland::Node::_ensure($node);
die "Cannot make a Node from an object of class $class\n"
unless $node;
return &RDF::Redland::CORE::librdf_model_context_remove_statements($self->{MODEL},$node);
}
=item contains_statement STATEMENT
Return non 0 if the model contains RDF::Redland::Statement I<STATEMENT>.
=cut
sub contains_statement ($$) {
my($self,$statement)=@_;
return &RDF::Redland::CORE::librdf_model_contains_statement($self->{MODEL},$statement->{STATEMENT});
}
=item as_stream [CONTEXT]
Return a new RDF::Redland::Stream object seralising the entire model,
or just those statements with I<CONTEXT>, as RDF::Redland::Statement
objects. If given, I<CONTEXT> can be a RDF::Redland::Node,
RDF::Redland::URI or perl URI object.
=cut
sub as_stream ($;$) {
my($self,$node)=@_;
my $stream;
if($node) {
my $class=ref($node);
$node=&RDF::Redland::Node::_ensure($node);
die "Cannot make a Node from an object of class $class\n"
unless $node;
$stream=&RDF::Redland::CORE::librdf_model_context_as_stream($self->{MODEL},
$node);
} else {
$stream=&RDF::Redland::CORE::librdf_model_as_stream($self->{MODEL});
}
return new RDF::Redland::Stream($stream,$self);
}
# Older names
sub serialise ($) { shift->as_stream; }
sub serialize ($) { shift->as_stream; }
=item find_statements STATEMENT [CONTEXT]
Find all matching statements in the model matching partial RDF::Redland::Statement
I<STATEMENT> (any of the subject, predicate, object RDF::Redland::Node can be undef).
If I<CONTEXT> is given, finds statements only in that context.
In an array context, returns an array of the matching RDF::Redland::Statement
objects. In a scalar context, returns the RDF::Redland::Stream object
representing the results.
=cut
sub find_statements ($$;$) {
my($self,$statement,$node)=@_;
my $stream;
if($node) {
my $class=ref($node);
$node=&RDF::Redland::Node::_ensure($node);
die "Cannot make a Node from an object of class $class\n"
unless $node;
$stream=&RDF::Redland::CORE::librdf_model_find_statements_in_context($self->{MODEL},$statement->{STATEMENT}, $node);
} else {
$stream=&RDF::Redland::CORE::librdf_model_find_statements($self->{MODEL},$statement->{STATEMENT});
}
my $user_stream=new RDF::Redland::Stream($stream,$self);
return $user_stream if !wantarray;
my(@results)=();
while(!$user_stream->end) {
push(@results, $user_stream->current);
$user_stream->next;
}
$user_stream=undef;
@results;
}
=item sources ARC TARGET
Get all source RDF::Redland::Node objects for a given arc I<ARC>, target I<TARGET>>
RDF::Redland::Node objects as a list of RDF::Redland::Node objects.
=cut
sub sources ($$$) {
my($self,$arc,$target)=@_;
my $iterator=&RDF::Redland::CORE::librdf_model_get_sources($self->{MODEL},$arc->{NODE},$target->{NODE});
return () if !$iterator;
my $user_iterator=new RDF::Redland::Iterator($iterator,$self,$arc,$target);
return () if !$user_iterator;
my(@results)=();
while(!$user_iterator->end) {
push(@results, $user_iterator->current);
$user_iterator->next;
}
$user_iterator=undef;
@results;
}
=item arcs SOURCE TARGET
Get all arc RDF::Redland::Node objects for a given source I<SOURCE>, target I<TARGET>
RDF::Redland::Node objects as a list of RDF::Redland::Node objects.
=cut
sub arcs ($$$) {
my($self,$source,$target)=@_;
my $iterator=&RDF::Redland::CORE::librdf_model_get_arcs($self->{MODEL},$source->{NODE},$target->{NODE});
return () if !$iterator;
my $user_iterator=new RDF::Redland::Iterator($iterator,$self,$source,$target);
return () if !$user_iterator;
my(@results)=();
while(!$user_iterator->end) {
push(@results, $user_iterator->current);
$user_iterator->next;
}
$user_iterator=undef;
@results;
}
=item targets SOURCE ARC
Get all target RDF::Redland::Node objects for a given source I<SOURCE>, arc I<ARC>
RDF::Redland::Node objects as a list of RDF::Redland::Node objects.
=cut
sub targets ($$$) {
my($self,$source,$arc)=@_;
my $iterator=&RDF::Redland::CORE::librdf_model_get_targets($self->{MODEL},$source->{NODE},$arc->{NODE});
return () if !$iterator;
my $user_iterator=new RDF::Redland::Iterator($iterator,$self,$source,$arc);
return () if !$user_iterator;
my(@results)=();
while(!$user_iterator->end) {
push(@results, $user_iterator->current);
$user_iterator->next;
}
$user_iterator=undef;
@results;
}
=item sources_iterator ARC TARGET
Get all source RDF::Redland::Node objects for a given arc I<ARC>, target
I<TARGET> RDF::Redland::Node objects as an RDF::Redland::Iterator or undef on failure.
=cut
sub sources_iterator ($$$) {
my($self,$arc,$target)=@_;
my $iterator=&RDF::Redland::CORE::librdf_model_get_sources($self->{MODEL},$arc->{NODE},$target->{NODE});
my $user_iterator=new RDF::Redland::Iterator($iterator,$self,$arc,$target);
$user_iterator;
}
=item arcs_iterator SOURCE TARGET
Get all arc RDF::Redland::Node objects for a given source I<SOURCE>, target
I<TARGET> RDF::Redland::Node objects as an RDF::Redland::Iterator or undef on failure.
=cut
sub arcs_iterator ($$$) {
my($self,$source,$target)=@_;
my $iterator=&RDF::Redland::CORE::librdf_model_get_arcs($self->{MODEL},$source->{NODE},$target->{NODE});
return new RDF::Redland::Iterator($iterator,$self,$source,$target);
}
=item targets_iterator SOURCE ARC
Get all target RDF::Redland::Node objects for a given source I<SOURCE>, arc I<ARC>
RDF::Redland::Node objects as an RDF::Redland::Iterator or undef on failure.
=cut
sub targets_iterator ($$$) {
my($self,$source,$arc)=@_;
my $iterator=&RDF::Redland::CORE::librdf_model_get_targets($self->{MODEL},$source->{NODE},$arc->{NODE});
return new RDF::Redland::Iterator($iterator,$self,$source,$arc);
}
=item source ARC TARGET
Get one source RDF::Redland::Node object that matches a given arc I<ARC>,
target I<TARGET> RDF::Redland::Node objects or undef if there is no match.
=cut
sub source ($$$) {
my($self,$arc,$target)=@_;
my $node=&RDF::Redland::CORE::librdf_model_get_source($self->{MODEL},$arc->{NODE},$target->{NODE});
return $node ? RDF::Redland::Node->_new_from_object($node,1) : undef;
}
=item arc SOURCE TARGET
Get one arc RDF::Redland::Node object that matches a given source I<SOURCE>,
target I<TARGET> RDF::Redland::Node objects or undef if there is no match.
=cut
sub arc ($$$) {
my($self,$source,$target)=@_;
my $node=&RDF::Redland::CORE::librdf_model_get_arc($self->{MODEL},$source->{NODE},$target->{NODE});
return $node ? RDF::Redland::Node->_new_from_object($node,1) : undef;
}
=item target SOURCE ARC
Get one target RDF::Redland::Node object that matches a given source
I<SOURCE>, arc I<ARC> RDF::Redland::Node objects or undef if there is no
match.
=cut
sub target ($$$) {
my($self,$source,$arc)=@_;
my $node=&RDF::Redland::CORE::librdf_model_get_target($self->{MODEL},$source->{NODE},$arc->{NODE});
return $node ? RDF::Redland::Node->_new_from_object($node,1) : undef;
}
=item contexts
Get all context RDF::Redland::Node objects in the model
=cut
sub contexts ($) {
my($self)=@_;
my $iterator=&RDF::Redland::CORE::librdf_model_get_contexts($self->{MODEL});
return () if !$iterator;
my $user_iterator=new RDF::Redland::Iterator($iterator,$self);
return () if !$user_iterator;
my(@results)=();
while(!$user_iterator->end) {
push(@results, $user_iterator->current);
$user_iterator->next;
}
$user_iterator=undef;
@results;
}
=item feature URI [VALUE]
Get/set a model feature. The feature is named via RDF::Redland::URI
I<URI> and the value is a RDF::Redland::Node. If I<VALUE> is given,
the feature is set to that value, otherwise the current value is
returned.
=cut
sub feature ($$;$) {
my($self,$uri,$value)=@_;
warn "RDF::Redland::Model->feature('$uri', '$value')\n" if $RDF::Redland::Debug;
$uri=RDF::Redland::URI->new($uri)
unless ref $uri;
return &RDF::Redland::CORE::librdf_model_set_feature($self->{MODEL},$uri->{URI},$value->{NODE})
if $value;
$value=&RDF::Redland::CORE::librdf_model_get_feature($self->{MODEL},$uri->{URI});
return $value ? RDF::Redland::Node->_new_from_object($value,1) : undef;
}
=item query_execute QUERY
Execute the I<QUERY> RDF::Redland::Query against the model returning
a result set RDF::Redland::QueryResults or undef on failure.
=cut
sub query_execute ($$) {
my($self,$query)=@_;
my $results = &RDF::Redland::CORE::librdf_model_query_execute($self->{MODEL}, $query->{QUERY});
return $results ? RDF::Redland::QueryResults->new($results) : undef;
}
=item load URI [SYNTAX-NAME [ MIME-TYPE [SYNTAX-URI [HANDLER ]]]
Load content from I<URI> into the model, guessing the parser.
=cut
sub load ($$;$$$$) {
my($self,$uri,$name,$type,$syntax_uri,$handler)=@_;
my $ruri=$uri ? $uri->{URI} : undef;
my $rsyntax_uri=$syntax_uri ? $syntax_uri->{URI} : undef;
if($handler) {
&RDF::Redland::set_log_handler($handler);
}
my $rc=&RDF::Redland::CORE::librdf_model_load($self->{MODEL},$ruri, $name, $type, $rsyntax_uri);
if($handler) {
&RDF::Redland::reset_log_handler();
}
return $rc;
}
=item to_string [BASE-URI [SYNTAX-NAME [ MIME-TYPE [SYNTAX-URI]]]
Serialize the model to a syntax. If no serializer name is given,
the default serializer RDF/XML is used.
=cut
sub to_string($;$$$$) {
my($self,$uri,$name,$type,$syntax_uri)=@_;
my $ruri=$uri ? $uri->{URI} : undef;
my $rsyntax_uri=$syntax_uri ? $syntax_uri->{URI} : undef;
return &RDF::Redland::CORE::librdf_model_to_string($self->{MODEL}, $ruri, $name, $type, $rsyntax_uri);
}
=pod
=back
=head1 OLDER METHODS
=over
=item serialise
=item serialize
Return a new RDF::Redland::Stream object seralising the model as
RDF::Redland::Statement objects. Replaced by as_stream to
reduce confusion with the RDF::Redland::Serializer class.
=back
=head1 SEE ALSO
L<RDF::Redland::Storage>, L<RDF::Redland::Node> and L<RDF::Redland::Statement>
=head1 AUTHOR
Dave Beckett - http://www.dajobe.org/
=cut
1;