You are viewing a plain text version of this content. The canonical link for it is here.
Posted to triplesoup-commits@incubator.apache.org by le...@apache.org on 2007/04/13 08:56:16 UTC
svn commit: r528394 [13/35] - in
/incubator/triplesoup/donations/TRIPLES-3-RDFStore: ./ dbms/ dbms/client/
dbms/client/t/ dbms/dbmsproxy/ dbms/deamon/ dbms/doc/ dbms/include/
dbms/libdbms/ dbms/utils/ doc/ include/ lib/ lib/DBD/ lib/RDFStore/
lib/RDFSt...
Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/DBMS.pm
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/DBMS.pm?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/DBMS.pm (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/DBMS.pm Fri Apr 13 01:56:01 2007
@@ -0,0 +1,167 @@
+# *
+# * Copyright (c) 2000-2006 Alberto Reggiori <ar...@webweaving.org>
+# * Dirk-Willem van Gulik <di...@webweaving.org>
+# *
+# * NOTICE
+# *
+# * This product is distributed under a BSD/ASF like license as described in the 'LICENSE'
+# * file you should have received together with this source code. If you did not get a
+# * a copy of such a license agreement you can pick up one at:
+# *
+# * http://rdfstore.sourceforge.net/LICENSE
+# *
+# *
+# * DBMS.pm -- Perl 5 interface to DBMS sockets
+# *
+# *
+=NAME DBMS
+
+=head1 NAME
+
+DBMS - Perl5 access to a dbms server.
+
+=head1 SYNOPSIS
+
+ use DBMS ;
+ $x=tie %hash, 'DBMS', $type,$name;
+
+ # Use the %hash array.
+ $hash{ aap } = noot;
+ foreach $k (keys(%hash)) {
+ print "$k - $hash{ $k }\n";
+ };
+ # and destroy..
+ undef $x;
+
+=head1 DESCRIPTION
+
+B<DBMS> is a module which allows Perl programs to make use of the
+facilities provided by the dbms server. The dbms server is a small
+server with a bit of glue to the Berkeley DB (> 1.85 < 2.x) and some code
+to listen to a few sockets.
+
+=head1 DETAILS
+
+As the devil is in the details... this module supports three
+functions which are not part of the normal tie interface;
+atomic counter increment, atomic counter decrement and atomic list retrival.
+
+The increment and decrement functions increments or decrement a counter before it returns
+a value. Thus a null or undef value can safely be taken as
+an error.
+
+=head2 EXAMPLE
+
+ use DBMS ;
+ $x=tie %hash, 'DBMS', $type,$name
+ or die "Could not ty to $name: $!";
+
+ $hash{ counter } = 0;
+
+ $my_id = $x->inc( 'counter' )
+ or die "Oi";
+
+ $my_id = $x->dec( 'counter' )
+ or die "Oi oi";
+
+ # and these are not quite implemented yet..
+ #
+ @keys = $x->keys();
+ @values = $x->values();
+ @all = $x->hash();
+
+=head1 VERSION
+
+$Id: DBMS.pm,v 1.5 2006/06/19 10:10:24 areggiori Exp $
+
+=head1 AVAILABILITY
+
+Well, ah hmmm. For ParlEuNet at the beginning but now for the whole CPAN community.
+
+=head1 BUGS
+
+Memory management not fully checked. Some speed issues, I.e. only
+about 100 TPS. No proper use of $! and $@, i.e. it will just croak,
+carp or return an undef. And there is no automagic retry should you
+loose the connection.
+
+=head1 Author
+
+Dirk-Willem van Gulik <di...@webweaving.org> and Alberto Reggiori <ar...@webweaving.org>
+
+=head1 SEE ALSO
+
+L<perl(1)>, L<DB_File(3)> L<AnyDBM_File(3)> L<perldbmfilter(3)>.
+
+=cut
+
+package DBMS;
+
+$E_NOSUCHDATABASE = 1011;
+
+use strict;
+use vars qw($VERSION @ISA $AUTOLOAD);
+
+use RDFStore; # load the underlying C code in RDFStore.xs because it is all in one module file
+
+use Carp;
+use Tie::Hash;
+use AutoLoader;
+@ISA = qw(Tie::Hash);
+
+$VERSION = "1.7";
+
+# some inlin-ed h2ph macros - need to be in-sync with dbms/include/dbms.h
+eval("sub DBMS::EVENT_RECONNECT () { 0; }") unless defined(&DBMS::EVENT_RECONNECT);
+eval("sub DBMS::EVENT_WAITING () { 1; }") unless defined(&DBMS::EVENT_WAITING);
+eval("sub DBMS::XSMODE_DEFAULT () { 0; }") unless defined(&DBMS::XSMODE_DEFAULT);
+eval("sub DBMS::XSMODE_RDONLY () { 1; }") unless defined(&DBMS::XSMODE_RDONLY);
+eval("sub DBMS::XSMODE_RDWR () { 2; }") unless defined(&DBMS::XSMODE_RDWR);
+eval("sub DBMS::XSMODE_CREAT () { 3; }") unless defined(&DBMS::XSMODE_CREAT);
+eval("sub DBMS::XSMODE_DROP () { 4; }") unless defined(&DBMS::XSMODE_DROP);
+
+
+# B-tree comparinson functions - see include/rdfstore_flat_store.h for definitions
+eval("sub DBMS::BT_COMP_INT () { 7000; }") unless defined(&DBMS::BT_COMP_INT);
+eval("sub DBMS::BT_COMP_DOUBLE () { 7001; }") unless defined(&DBMS::BT_COMP_DOUBLE);
+eval("sub DBMS::BT_COMP_DATE () { 7002; }") unless defined(&DBMS::BT_COMP_DATE);
+
+sub inc {
+ my($class,$key)=@_;
+ return $class->INC($key);
+};
+
+sub dec {
+ my($class,$key)=@_;
+ return $class->DEC($key);
+};
+
+sub isalive {
+ my($class,$key)=@_;
+ return $class->PING($key);
+};
+
+sub drop {
+ my($class,$key)=@_;
+ return $class->DROP($key);
+};
+
+sub AUTOLOAD {
+ my($constname);
+ ($constname = $AUTOLOAD) =~ s/.*:://;
+ my $val = constant($constname, @_ ? $_[0] : 0);
+ if ($! != 0) {
+ if ($! =~ /Invalid/) {
+ $AutoLoader::AUTOLOAD = $AUTOLOAD;
+ goto &AutoLoader::AUTOLOAD;
+ }
+ else {
+ Carp::croak("Your vendor has not defined DBMS macro $constname, used");
+ }
+ }
+ eval "sub $AUTOLOAD { $val }";
+ goto &$AUTOLOAD;
+}
+
+1;
+__END__
Propchange: incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/DBMS.pm
------------------------------------------------------------------------------
svn:executable = *
Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/RDFStore/Digest/Digestable.pm
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/RDFStore/Digest/Digestable.pm?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/RDFStore/Digest/Digestable.pm (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/RDFStore/Digest/Digestable.pm Fri Apr 13 01:56:01 2007
@@ -0,0 +1,50 @@
+# *
+# * Copyright (c) 2000-2004 Alberto Reggiori <ar...@webweaving.org>
+# * Dirk-Willem van Gulik <di...@webweaving.org>
+# *
+# * NOTICE
+# *
+# * This product is distributed under a BSD/ASF like license as described in the 'LICENSE'
+# * file you should have received together with this source code. If you did not get a
+# * a copy of such a license agreement you can pick up one at:
+# *
+# * http://rdfstore.sourceforge.net/LICENSE
+# *
+# * Changes:
+# * version 0.1 - Wed May 23 18:16:29 CEST 2001
+# *
+
+package RDFStore::Digest::Digestable;
+{
+use vars qw ($VERSION);
+use strict;
+
+$VERSION = '0.1';
+
+sub new {
+ bless {} , shift;
+};
+
+sub getDigest {
+};
+
+1;
+};
+
+__END__
+
+=head1 NAME
+
+RDFStore::Digest::Digestable - implementation of the Digestable RDF API
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+=head1 SEE ALSO
+
+Digest(3)
+
+=head1 AUTHOR
+
+ Alberto Reggiori <ar...@webweaving.org>
Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/RDFStore/Literal.pm
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/RDFStore/Literal.pm?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/RDFStore/Literal.pm (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/RDFStore/Literal.pm Fri Apr 13 01:56:01 2007
@@ -0,0 +1,143 @@
+# *
+# * Copyright (c) 2000-2006 Alberto Reggiori <ar...@webweaving.org>
+# * Dirk-Willem van Gulik <di...@webweaving.org>
+# *
+# * NOTICE
+# *
+# * This product is distributed under a BSD/ASF like license as described in the 'LICENSE'
+# * file you should have received together with this source code. If you did not get a
+# * a copy of such a license agreement you can pick up one at:
+# *
+# * http://rdfstore.sourceforge.net/LICENSE
+# *
+# * Changes:
+# * version 0.1 - 2000/11/03 at 04:30 CEST
+# * version 0.2
+# * - modified new() equals(), getLabel() methods accordingly to rdf-api-2000-10-30
+# * - modified toString()
+# * version 0.3
+# * - fixed bugs when checking references/pointers (defined and ref() )
+# * version 0.4
+# * - updated accordingly to rdf-api-2001-01-19
+# * - modified getLabel() and getURI() to return a lebel even if the Literal is a BLOB (using Storable)
+# * - updated equals() method to make a real comparison of BLOBs using Storable module
+# * version 0.41
+# * - added getDigest() to generate the digest using quotes and the label
+# * version 0.42
+# * - updated accordingly to new RDFStore API
+# * - removed BLOB support
+# *
+
+package RDFStore::Literal;
+{
+use vars qw ($VERSION);
+use strict;
+
+use Carp;
+
+$VERSION = '0.42';
+
+use Carp;
+use RDFStore; # load the underlying C code in RDFStore.xs because it is all in one module file
+use RDFStore::RDFNode;
+
+sub equals {
+ return 0
+ unless(defined $_[1]);
+
+ return 0
+ if ( ref($_[1]) =~ /^(SCALAR|ARRAY|HASH|CODE|REF|GLOB|LVALUE)/ ); #see perldoc perlfunc ref()
+
+ my $label1 = $_[0]->getLabel();
+ my $label2;
+ if( ($_[1]) &&
+ (ref($_[1])) &&
+ ($_[1]->isa("RDFStore::Literal")) ) {
+ $label2 = $_[1]->getLabel();
+ } else {
+ $label2 = $_[1];
+ };
+
+ return ($label1 eq $label2) ? 1 : 0;
+ };
+
+1;
+};
+
+__END__
+
+=head1 NAME
+
+RDFStore::Literal - An RDF Literal Node implementation
+
+=head1 SYNOPSIS
+
+ use RDFStore::Literal;
+ my $literal = new RDFStore::Literal('Tim Berners-Lee');
+ my $literal1 = new RDFStore::Literal('Today is a sunny day, again :)');
+
+ print $literal->toString." is ";
+ print "not"
+ unless $literal->equals($literal1);
+ print " equal to ".$literal1->toString."\n";
+
+=head1 DESCRIPTION
+
+An RDF Literal Node implementation using Storable(3). A Literal object can either contain plain (utf8) strings. Such an implementation allows to create really generic RDF statements about Perl data-structures or objects for example. Generally an RDFStore::Literal can be thought like an atomic perl scalar.
+XML well-formed literal values are supported simply by storing the resulting utf8 bytes into a perl scalar; none methods are being provided tomanage literals as XML (e.g. SAX2 events and stuff like that)
+
+=head1 METHODS
+
+=over 4
+
+=item new ( LITERAL )
+
+This is a class method, the constructor for RDFStore::Literal. The only parameter passed is either a plain perl scalar (LITERAL)
+
+=item getParseType
+
+Return the parseType of the RDF Literal; possible values are I<Literal> or I<Resource> (B<default>).
+
+=item getLang
+
+Return the language of the RDF Literal eventually coming from xml:lang attribute on parsing.
+
+=item getDataType
+
+Return the RDFStore::Resource representing the XMLSchema data type of the RDF Literal.
+
+=item getLabel
+
+Return the literal text of the node.
+
+=item getDigest
+
+Return a Cryptographic Digest (SHA-1 by default) of the RDF Literal; the actual digest message is guranteed to be different for URI representing RDF Resources or RDF Literals.
+
+=item equals
+
+Compare two literals.
+
+=head1 SEE ALSO
+
+RDFStore::RDFNode(3)
+
+=head1 ABOUT RDF
+
+ http://www.w3.org/TR/rdf-primer/
+
+ http://www.w3.org/TR/rdf-mt
+
+ http://www.w3.org/TR/rdf-syntax-grammar/
+
+ http://www.w3.org/TR/rdf-schema/
+
+ http://www.w3.org/TR/1999/REC-rdf-syntax-19990222 (obsolete)
+
+=head1 BUGS
+
+The language of the literal as recently specified by the RDF Core WG is not supported and the typed literals are not implemented; the latter is due mainly because perl is an untyped language and perhaps such data-typing abstractions should fit in a higher level application specific API.
+
+=head1 AUTHOR
+
+ Alberto Reggiori <ar...@webweaving.org>
Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/RDFStore/Model.pm
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/RDFStore/Model.pm?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/RDFStore/Model.pm (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/RDFStore/Model.pm Fri Apr 13 01:56:01 2007
@@ -0,0 +1,1494 @@
+# *
+# * Copyright (c) 2000-2006 Alberto Reggiori <ar...@webweaving.org>
+# * Dirk-Willem van Gulik <di...@webweaving.org>
+# *
+# * NOTICE
+# *
+# * This product is distributed under a BSD/ASF like license as described in the 'LICENSE'
+# * file you should have received together with this source code. If you did not get a
+# * a copy of such a license agreement you can pick up one at:
+# *
+# * http://rdfstore.sourceforge.net/LICENSE
+# *
+# * Changes:
+# * version 0.1 - 2000/11/03 at 04:30 CEST
+# * version 0.2
+# * - fixed bug in new() to check if triples is HASH ref when passed by user
+# * - fixed bug in find() do avoid to return instances of SetModel (see SchemaModel.pm also)
+# * Now result sets are put in an object(model) of the the same type - see find()
+# * - modified add() remove() clone() duplicate() and added toString() makePrivate()
+# * getNamespace() getLocalName() methods accordingly to rdf-api-2000-10-30
+# * - modifed new(), duplicate(), clone() and find() to support cloned models
+# * Due the fact that Data::MagicTie does not support the clone method, when
+# * either the triples or the index are duplicated (or cloned) the user could
+# * specify on which HASH(es) (tied or not) to store the results (see duplicate())
+# * - modified find() to manage normal Models and indexed Models differently
+# * - added optional indirect indexing to find() i.e. the FindIndex stores just digested keys
+# * and not the full BLOB; fetch from an index then require an additional look up in triples
+# * version 0.3
+# * - fixed bug in find(). Check the type of $t before using methods on it
+# * - added toStrawmanRDF() to serialise the model in strawman RDF for RDFStore::Parser::OpenHealth
+# * - fixed bug in create()
+# * - fixed bugs when checking references/pointers (defined and ref() )
+# * - modified updateDigest() method accordingly to rdf-api-2000-11-13
+# * version 0.31
+# * - commented out isEmpty() check in find() due to DBMS(3) efficency problems
+# * - fixed bug in add() when adding statements with a Literal value
+# * - updated toStrawmanRDF() method
+# * - modifed add() to avoid update of existing statements
+# * version 0.4
+# * - modifed add() to return undef if the triples exists already in the database
+# * - changed way to return undef in subroutines
+# * - renamed triples hash to store
+# * - adapted to use the new Data::MagicTie interface
+# * - complete re-design of the indexing and storage method
+# * - added getOptions() method
+# * - Devon Smith <de...@taller.pscl.cwru.edu> changed getDigestBytes() to generate digests and hashes
+# * that match Stanford java ones exactly
+# * - added inheritance from RDFStore::Digest::Digestable
+# * - removed RDFStore::Resource inheritance
+# * version 0.41
+# * - updated _getLookupValue() and _getValuesFromLookup() to consider negative hashcodes
+# * version 0.42
+# * - complete redesign of the indexing method up to free-text search on literals
+# * - added tied array iterator RDFStore::Model::Statements to allow fetching results one by one
+# * - modified find() to allow a 4th paramater to make free-text search over literals
+# * version 0.43
+# * - brand new design now using the faster C/XS RDFStore(3) module....finally :)
+# * - updated methods to avoid a full copy of statements across when the model is shared if possible
+# * - added basic support for statements grouping - see setContext(), getContext() and resetContext()
+# * - zapped toStrawmanRDF() method
+# * - added serialize() method to generally dump a model/graph to a string or filehanlde
+# * - added isConnected() and isRemote() methods
+# * - added unite(), subtract(), intersect(), complement() and exor() methods
+# * - re-added RDFStore::Resource inheritance
+# * - added getParser(), getReader(), getSerializer() and getWriter() methods
+# * version 0.44
+# * - updated search() method call to use new XS code interface (hash ref)
+# * - added ifModifiedSince() method
+# *
+
+package RDFStore::Model;
+{
+use vars qw ($VERSION);
+use strict;
+
+$VERSION = '0.44';
+
+use Carp;
+
+use RDFStore;
+use RDFStore::Digest::Digestable;
+use RDFStore::Literal;
+use RDFStore::Resource;
+use RDFStore::Object;
+use RDFStore::Statement;
+use RDFStore::NodeFactory;
+use RDFStore::Parser::SiRPAC;
+use RDFStore::Parser::NTriples;
+use RDFStore::Serializer::RDFXML;
+use RDFStore::Serializer::NTriples;
+use RDFStore::Util::Digest;
+
+@RDFStore::Model::ISA = qw( RDFStore::Resource RDFStore::Digest::Digestable );
+
+sub new {
+ my ($pkg,%params) = @_;
+
+ my $self = {};
+
+ # first operation creates lookup table
+ $self->{nodeFactory}=( (exists $params{nodeFactory}) &&
+ (defined $params{nodeFactory}) &&
+ (ref($params{nodeFactory})) &&
+ ($params{nodeFactory}->isa("RDFStore::NodeFactory")) ) ?
+ $params{nodeFactory} : new RDFStore::NodeFactory();
+
+ $self->{options} = \%params;
+
+ #store
+ my @params = ();
+
+ if ( (exists $params{Name}) &&
+ (defined $params{Name}) ) {
+ push @params, $params{Name};
+ } else {
+ push @params,undef;
+ };
+ if ( (exists $params{Mode}) &&
+ (defined $params{Mode}) ) {
+ push @params, ($params{Mode} eq 'r') ? 1 : 0;
+ } else {
+ push @params,0;
+ };
+ if ( (exists $params{FreeText}) &&
+ (defined $params{FreeText}) ) {
+ push @params, ($params{FreeText} =~ /(1|on|yes|true)/i) ? 1 : 0;
+ } else {
+ push @params,0;
+ };
+ if ( (exists $params{Sync}) &&
+ (defined $params{Sync}) ) {
+ push @params, int($params{Sync});
+ } else {
+ push @params,0;
+ };
+ if ( ( (exists $params{Host}) &&
+ (defined $params{Host}) ) ||
+ ( (exists $params{Port}) &&
+ (defined $params{Port}) ) ) {
+ push @params, 1;
+ } else {
+ push @params, 0;
+ };
+ if ( (exists $params{Host}) &&
+ (defined $params{Host}) ) {
+ push @params, $params{Host};
+ } else {
+ push @params,undef;
+ };
+ if ( (exists $params{Port}) &&
+ (defined $params{Port}) ) {
+ push @params, $params{Port};
+ } else {
+ push @params,undef;
+ };
+
+ $self->{'rdfstore'} = new RDFStore( @params );
+
+ die "Cannot connect rdfstore"
+ unless( (defined $self->{rdfstore}) &&
+ (ref($self->{rdfstore})) &&
+ ($self->{rdfstore}->isa("RDFStore")) );
+
+ $self->{'rdfstore_params'} = \%params;
+
+ bless $self,$pkg;
+
+ return $self;
+};
+
+# set a context for the statements (i.e. each asserted statement will get such a context automatically)
+# NOTE: this stuff I can not still understand how could be related to reification/logic/inference but it should...
+sub setContext {
+ my ($class,$context)=@_;
+
+ $class->{rdfstore}->set_context( $context );
+ };
+
+# reset the context for the statements (i.e. each asserted statement will be in a *empty* context after calling this method)
+sub resetContext {
+ my ($class)=@_;
+
+ $class->{rdfstore}->reset_context;
+ };
+
+#return actual defined context of the model
+sub getContext {
+ my ($class)=@_;
+
+ my $ctx = $class->{rdfstore}->get_context;
+
+ return
+ unless($ctx);
+
+ return ($ctx->isbNode) ? $class->{nodeFactory}->createAnonymousResource($ctx->toString) : $class->{nodeFactory}->createResource($ctx->toString);
+ };
+
+# return model options
+sub getOptions {
+ return %{$_[0]->{'options'}};
+ };
+
+sub isAnonymous {
+ return 0;
+ };
+
+sub getNamespace {
+ return undef;
+ };
+
+sub getLocalName {
+ return $_[0]->getURI();
+ };
+
+sub toString {
+ return "Model[".$_[0]->getSourceURI()."]";
+ };
+
+# Set a base URI for the model
+sub setSourceURI {
+ $_[0]->{rdfstore}->set_source_uri( ( (ref($_[1])) && ($_[1]->isa("RDFStore::Resource")) ) ? $_[1]->toString : $_[1] );
+ # we shuld probably set it as default context eventually but I am not sure....
+ };
+
+# Returns current base URI for the model
+sub getSourceURI {
+ $_[0]->{rdfstore}->get_source_uri;
+ };
+
+# model access methods
+
+# return the number of triples in the model
+sub size {
+ if( (exists $_[0]->{Shared}) &&
+ (defined $_[0]->{Shared}) ) {
+ if(exists $_[0]->{query_iterator}) {
+ return $_[0]->{query_iterator}->size;
+ } else {
+ return $_[0]->{Shared}->size;
+ };
+ };
+
+ $_[0]->{rdfstore}->size;
+ };
+
+# check whether or not the model is empty
+sub isEmpty {
+ if( (exists $_[0]->{Shared}) &&
+ (defined $_[0]->{Shared}) ) {
+ if(exists $_[0]->{query_iterator}) {
+ return ( $_[0]->{query_iterator}->size > 0 ) ? 0 : 1;
+ } else {
+ return $_[0]->{Shared}->isEmpty;
+ };
+ };
+ $_[0]->{rdfstore}->is_empty;
+ };
+
+sub isConnected {
+ if( (exists $_[0]->{Shared}) &&
+ (defined $_[0]->{Shared}) ) {
+ return $_[0]->{Shared}->isConnected;
+ };
+ $_[0]->{rdfstore}->is_connected;
+ };
+
+sub isRemote {
+ if( (exists $_[0]->{Shared}) &&
+ (defined $_[0]->{Shared}) ) {
+ return $_[0]->{Shared}->isRemote;
+ };
+ $_[0]->{rdfstore}->is_remote;
+ };
+
+sub ifModifiedSince {
+ if( (exists $_[0]->{Shared}) &&
+ (defined $_[0]->{Shared}) ) {
+ return $_[0]->{Shared}->ifModifiedSince( $_[1] );
+ };
+
+ &RDFStore::if_modified_since( $_[0]->{'rdfstore_params'}->{'Name'}, $_[1] );
+ };
+
+# return an instance of RDFStore::Model::Iterator
+sub elements {
+ my ($class) = @_;
+
+ if( (exists $class->{Shared}) &&
+ (defined $class->{Shared}) ) {
+ if(exists $class->{query_iterator}) {
+ if( ($class->{query_iterator}->size > 0 ) &&
+ (defined $class->{query}) &&
+ (ref($class->{query})=~/ARRAY/) ) {
+ delete($class->{query});
+ };
+ # iterator over result set
+ return RDFStore::Model::Iterator->new( $class->getNodeFactory,
+ $class->{query_iterator} );
+ } else {
+ return $class->{Shared}->elements;
+ };
+ } else {
+ # normal iterator over the whole model
+ return RDFStore::Model::Iterator->new( $class->getNodeFactory,
+ $class->{rdfstore}->elements );
+ };
+ };
+
+sub namespaces {
+ my ($class) = @_;
+
+ my %ns_table=();
+
+ # must scan the whole database of course :-(
+ my $itr = $class->elements;
+ while ( my $p = $itr->each_predicate ) {
+ my $ns_uri = $p->getNamespace;
+
+ next
+ unless(defined $ns_uri);
+
+ $ns_table{ $ns_uri } = 1
+ unless(exists $ns_table{ $ns_uri });
+ };
+
+ return keys %ns_table;
+ };
+
+# tests if the model contains a given statement
+sub contains {
+ return 0
+ unless( (defined $_[1]) &&
+ (ref($_[1])) &&
+ ($_[1]->isa("RDFStore::Statement")) );
+
+ croak "Statement context '".$_[2]."' is not instance of RDFStore::Resource"
+ unless( (not(defined $_[2])) ||
+ ( (defined $_[2]) &&
+ (ref($_[2])) &&
+ ($_[2]->isa('RDFStore::Resource')) ) );
+
+ my $context;
+ if(defined $_[2]) {
+ $context = $_[2];
+ } else {
+ $context = $_[1]->context
+ if($_[1]->context);
+ };
+
+ if( (exists $_[0]->{Shared}) &&
+ (defined $_[0]->{Shared}) ) {
+ if(exists $_[0]->{query_iterator}) {
+ return 0
+ if($_[0]->{query_iterator}->size <= 0); #got an empty query
+
+ # simply use the iterator we got from last query to quickly (??) check whether or not the st_id exists in the rdfstore; efficient, really??
+ return $_[0]->{query_iterator}->contains( $_[1], undef, undef, $context );
+ } else {
+ return ( $_[0]->find( $_[1]->subject, $_[1]->predicate, $_[1]->object, $context )->elements->size == 1 );
+ };
+ };
+
+ return $_[0]->{rdfstore}->contains( $_[1], undef, undef, $context );
+ };
+
+# Model manipulation: add, remove, find
+#
+# NOTE: it is not really safe here - we might need to lock all DBs, add statement, unlock and return (TXP) :)
+#
+# Adds a new triple to the model
+sub add {
+ my ($class, $subject,$predicate,$object,$context) = @_;
+
+ croak "Subject or Statement '".$subject."' is either not instance of RDFStore::Statement or RDFStore::Resource"
+ unless( (defined $subject) &&
+ (ref($subject)) &&
+ ( ($subject->isa('RDFStore::Resource')) ||
+ ($subject->isa('RDFStore::Statement')) ) );
+ croak "Predicate '".$predicate."' is not instance of RDFStore::Resource"
+ unless( (not(defined $predicate)) ||
+ ( (defined $predicate) &&
+ (ref($predicate)) &&
+ ($predicate->isa('RDFStore::Resource')) ) );
+ croak "Object '".$object."' is not instance of RDFStore::RDFNode"
+ unless( (not(defined $object)) ||
+ ( ( (defined $object) &&
+ (ref($object)) &&
+ ($object->isa('RDFStore::RDFNode'))) ||
+ ( (defined $object) &&
+ ($object !~ m/^\s+$/) ) ) );
+
+ croak "Statement context '".$context."' is not instance of RDFStore::Resource"
+ unless( (not(defined $context)) ||
+ ( (defined $context) &&
+ (ref($context)) &&
+ ($context->isa('RDFStore::Resource')) ) );
+
+ if( (defined $subject) &&
+ (ref($subject)) &&
+ ($subject->isa("RDFStore::Statement")) &&
+ (not(defined $predicate)) &&
+ (not(defined $object)) ) {
+ $context = $subject->context
+ unless(defined $context);
+ ($subject,$predicate,$object) = ($subject->subject, $subject->predicate, $subject->object);
+ } elsif( (defined $object) &&
+ (!(ref($object))) ) {
+ $object = $class->{nodeFactory}->createLiteral($object);
+ };
+
+ if( (exists $class->{Shared}) &&
+ (defined $class->{Shared}) ) {
+ if(exists $class->{query_iterator}) {
+ # simply use the iterator we got from last query to quickly (??) check whether or not the st_id exists in the rdfstore
+ # this should save the expensive _copyOnWrite() below eventually
+ return 0 #is it working also for empty queries???!
+ if ( $class->{query_iterator}->contains( $subject, $predicate, $object, $context ) );
+ };
+ # copy across stuff if necessary
+ $class->_copyOnWrite();
+ };
+
+ my $status = $_[0]->{rdfstore}->insert( $subject, $predicate, $object, $context );
+
+ $class->updateDigest($subject,$predicate,$object,$context); #add context to updateDigest() as well???
+
+ return $status;
+ };
+
+sub updateDigest {
+ delete $_[0]->{digest};
+
+ #return
+ # unless(defined $_[0]->{digest});
+ # see http://nestroy.wi-inf.uni-essen.de/rdf/sum_rdf_api/#K31
+ #my $digest = $_[1]->getDigest();
+ #RDFStore::Util::Digest::xor($_[0]->getDigest(),$digest->getDigest());
+ };
+
+# Removes the triple from the model
+# NOTE: it is not really safe here - we might need to lock all DBs, del statement, unlock and return (TXP) :)
+sub remove {
+ croak "Statement '".$_[1]."' is not instance of RDFStore::Statement"
+ unless( (defined $_[1]) &&
+ (ref($_[1])) &&
+ ($_[1]->isa('RDFStore::Statement')) );
+
+ croak "Statement context '".$_[2]."' is not instance of RDFStore::Resource"
+ unless( (not(defined $_[2])) ||
+ ( (defined $_[2]) &&
+ (ref($_[2])) &&
+ ($_[2]->isa('RDFStore::Resource')) ) );
+
+ my $context;
+ if(defined $_[2]) {
+ $context = $_[2];
+ } else {
+ $context = $_[1]->context
+ if($_[1]->context);
+ };
+
+ # copy across stuff if necessary
+ $_[0]->_copyOnWrite()
+ if( (exists $_[0]->{Shared}) &&
+ (defined $_[0]->{Shared}) );
+
+ my $status = $_[0]->{rdfstore}->remove( $_[1], undef, undef, $context );
+
+ $_[0]->updateDigest($_[1]->subject, $_[1]->predicate, $_[1]->object, $context);
+
+ return $status;
+ };
+
+sub isMutable {
+ return 1;
+ };
+
+# General method to search for triples.
+# null input for any parameter will match anything.
+# Example: $result = $m->find( undef, $RDFStore::Vocabulary::RDF::type, new RDFStore::Resource("http://...#MyClass"), [ context, words_operator, @words ] );
+# finds all instances in the model
+sub find {
+ my ($class) = shift;
+ my ($subject,$predicate,$object,$context,$words_operator,@words) = @_;
+
+ croak "Subject '".$subject."' is not instance of RDFStore::Resource"
+ unless( (not(defined $subject)) ||
+ ( (defined $subject) &&
+ (ref($subject)) &&
+ ($subject->isa('RDFStore::Resource')) ) );
+ croak "Predicate '".$predicate."' is not instance of RDFStore::Resource"
+ unless( (not(defined $predicate)) ||
+ ( (defined $predicate) &&
+ (ref($predicate)) &&
+ ($predicate->isa('RDFStore::Resource')) ) );
+ croak "Object '".$object."' is not instance of RDFStore::RDFNode"
+ unless( (not(defined $object)) ||
+ ( (defined $object) &&
+ (ref($object)) &&
+ ($object->isa('RDFStore::RDFNode')) ) );
+
+ croak "Statement context '".$context."' is not instance of RDFStore::Resource"
+ unless( (not(defined $context)) ||
+ ( (defined $context) &&
+ (ref($context)) &&
+ ($context->isa('RDFStore::Resource')) ) );
+
+ # e.g. $class->find($subject,$predicate,$object)->find(....) and so on
+ # NOTE: we are trying to improve this by avoiding DB operations using shared_ids of statements/properties.....
+ if( (exists $class->{Shared}) &&
+ (defined $class->{Shared}) ) {
+ $class->{Shared}->{sharing_query_iterator} = $class->{query_iterator}->duplicate
+ if(exists $class->{query_iterator});
+ return $class->{Shared}->find($subject,$predicate,$object,$context,$words_operator,@words);
+ };
+
+ my @query = @_;
+ $class->{query} = \@query;
+
+ # we have the same problem like in Pen - a result set must be a model/collection :-)
+ my $res = $class->create(); #EMPTY MODEL
+
+ #skip 2 FETCHES for the moment - efficency
+ #return $res
+ # if($class->{rdfstore}->is_empty());
+
+ #share IDs till first write operation such as add() or remove() on query result model
+ # NOTE: sharing avoid add() full-blown statements to the result model
+ $res->{Shared}=$class;
+
+ $res->setContext( $context ) #correct ???!!???
+ if(defined $context);
+
+ if( (not(defined $subject)) &&
+ (not(defined $predicate)) &&
+ (not(defined $object)) &&
+ (not(defined $context)) &&
+ ($#words < 0) ) {
+ # does NOT work for shared models yet!!!! - note: the duplicate() above could have fixed it :)
+ if ( exists $class->{sharing_query_iterator}) {
+ $res->{query_iterator} = $class->{sharing_query_iterator};
+ delete $class->{sharing_query_iterator};
+
+ return $res;
+ } else {
+ my $d = $class->duplicate();
+ #$d->setContext( $context ) #correct???!??
+ # if(defined $context); #impossible
+ return $d;
+ };
+ };
+
+ #all non-words operators are set to 0=OR - will need 1=AND for real RDQL query
+ my $query = { 'search_type' => 0, #default triple-pattern search
+ "s" => [],
+ "s_op" => "or",
+ "p" => [],
+ "p_op" => "or",
+ "o" => [],
+ "o_op" => "or",
+ "c" => [],
+ "c_op" => "or",
+ "xml:lang" => [],
+ "xml:lang_op" => "or",
+ "rdf:datatype" => [],
+ "rdf:datatype_op" => "or"
+ };
+
+ my @qq=();
+ if($subject) {
+ push @{$query->{'s'}}, $subject;
+ };
+ if($predicate) {
+ push @{$query->{'p'}}, $predicate;
+ };
+ if($object) {
+ push @{$query->{'o'}}, $object;
+ #still need to add xml:lang and rdf:datatype for passed object here...
+ };
+ if($context) {
+ push @{$query->{'c'}}, $context;
+ };
+ $query->{'words_op'} = ( (defined $words_operator) &&
+ ($words_operator =~ /(and|&|1)/i) ) ? 'and' :
+ ( (defined $words_operator) &&
+ ($words_operator =~ /(not|~|2)/i) ) ? 'not' : 'or' ;
+
+ push @{$query->{'words'}}, @words;
+
+ my $iterator = $class->{rdfstore}->search( $query );
+
+ if ( exists $class->{sharing_query_iterator}) {
+ # intersect/diff the two iterators
+ $res->{query_iterator} = $class->{sharing_query_iterator}->intersect( $iterator );
+ delete $class->{sharing_query_iterator};
+ } else {
+ $res->{query_iterator} = $iterator;
+ };
+
+ return $res;
+ };
+
+sub fetch_object {
+ my ($class,$resource,$context) = @_;
+
+ croak "Resource '".$resource."' is not instance of RDFStore::Resource"
+ unless( (defined $resource) &&
+ (ref($resource)) &&
+ ($resource->isa('RDFStore::Resource')) );
+
+ croak "Context '".$context."' is not instance of RDFStore::Resource"
+ unless( (not(defined $context)) ||
+ ( (defined $context) &&
+ (ref($context)) &&
+ ($context->isa('RDFStore::Resource')) ) );
+
+ return
+ if( $resource->isbNode );
+
+ # we have the same problem like in Pen - a result set must be a model/collection :-)
+ my $res = $class->create(); #EMPTY MODEL
+
+ #share IDs till first write operation such as add() or remove() on query result model
+ # NOTE: sharing avoid add() full-blown statements to the result model
+ $res->{Shared}=$class;
+
+ $res->setContext( $context ) #correct ???!!???
+ if(defined $context);
+
+#print "FETCH --> ".$resource->toString."\n";
+ $res->{query_iterator} = $class->{rdfstore}->fetch_object( ($resource->isa("RDFStore::Object")) ? $resource->{'rdf_object'} : $resource, $context );
+
+ return $res;
+ };
+
+sub getResource {
+ my ($class,$resource) = @_;
+
+ my $object = new RDFStore::Object( $resource );
+ $object->load( $class->fetch_object( $class->getNodeFactory->createResource($resource) ) );
+
+ return $object; #return a new in-memory RDF object (and relative model)
+ };
+
+# clone the model - So due that copy is expensive we use sharing :)
+sub duplicate {
+ my ($class) = @_;
+
+ return $class->{Shared}->duplicate
+ if( (exists $class->{Shared}) &&
+ (defined $class->{Shared}) );
+
+ my $new = $class->create();
+
+ # return a model that shares store and lookup with this model
+ # delegate read operations till first write operation such as add() or remove()
+ # NOTE: sharing avoid to copy right the way the whole original model that could be very large :)
+ # This trick allows to chain nicely find() methods
+ $new->{Shared} = $class;
+
+ # set default context if any was set
+ my $sg = $class->getContext;
+ $new->setContext( $sg )
+ if(defined $sg);
+ return $new;
+};
+
+# Creates in-memory empty model with the same options but Sync
+sub create {
+ my($class) = shift;
+
+ my $self = ref($class);
+ my $new = $self->new(); #we also get empty RDFStore(3)
+
+ return $new;
+ };
+
+sub getNodeFactory {
+ return $_[0]->{nodeFactory};
+ };
+
+sub getLabel {
+ return $_[0]->getURI;
+ };
+
+sub getURI {
+ if($_[0]->isEmpty()) {
+ return $_[0]->{nodeFactory}->createUniqueResource()->toString();
+ } else {
+ return "urn:rdf:".
+ &RDFStore::Util::Digest::getDigestAlgorithm()."-".
+ unpack("H*", $_[0]->getDigest() );
+ };
+ };
+
+sub getDigest {
+ unless ( defined $_[0]->{digest} ) {
+ sub digest_sorter {
+ my @a1 = unpack "c*",$a->getDigest();
+ my @b1 = unpack "c*",$b->getDigest();
+ my $i;
+ for ($i=0; $i < $#a1 +1; $i++) {
+ return $a1[$i] - $b1[$i] unless ord $a1[$i] == ord $b1[$i];
+ };
+ return 0;
+ };
+ my $t;
+ my $digest_bytes;
+ my ($el) = $_[0]->elements;
+ my @sts = ();
+ my $ss;
+ for ( $ss = $el->first;
+ $el->hasnext;
+ $ss = $el->next ) {
+ push @sts, $ss;
+ };
+ for $t ( sort digest_sorter @sts ){ #this still fetches all statements in-memory :(
+ $digest_bytes .= $t->getDigest();
+ };
+ $_[0]->{digest} = RDFStore::Util::Digest::computeDigest($digest_bytes);
+ };
+ return $_[0]->{digest};
+ };
+
+#set operations on RDFStore::Model using RDFStore::Iterator (mostly efficient in-memory)
+sub intersect {
+ my ($class,$other) = @_;
+
+ return
+ unless($other);
+
+ croak "Model '".$other."' is not instance of RDFStore::Model"
+ unless( (defined $other) && (ref($other)) &&
+ ($other->isa('RDFStore::Model')) );
+
+ croak "Models can not be intersected"
+ unless( ( $class->{Shared} == $class->{Shared} ) ||
+ ( $class->{rdfstore} == $other->{rdfstore} ) );
+
+ my $res = $class->create(); #EMPTY MODEL in-memory
+
+ $res->{Shared} = $class; # share storage (the other is sharing it anyway by definition :-)
+
+ my $iter = $class->elements->intersect( $other->elements ); # that easy :)
+
+ return
+ unless($iter);
+
+ $res->{query_iterator} = $iter->{iterator};
+
+ # set default context if any was set
+ my $sg = $class->getContext;
+ $res->setContext( $sg )
+ if(defined $sg);
+
+ return $res;
+ };
+
+sub subtract {
+ my ($class,$other) = @_;
+
+ return
+ unless($other);
+
+ croak "Model '".$other."' is not instance of RDFStore::Model"
+ unless( (defined $other) && (ref($other)) &&
+ ($other->isa('RDFStore::Model')) );
+
+ croak "Models can not be subtracted"
+ unless( ( $class->{Shared} == $class->{Shared} ) ||
+ ( $class->{rdfstore} == $other->{rdfstore} ) );
+
+ my $res = $class->create(); #EMPTY MODEL in-memory
+
+ $res->{Shared} = $class; # share storage (the other is sharing it anyway by definition :-)
+
+ my $iter = $class->elements->subtract( $other->elements );
+
+ return
+ unless($iter);
+
+ $res->{query_iterator} = $iter->{iterator};
+
+ # set default context if any was set
+ my $sg = $class->getContext;
+ $res->setContext( $sg )
+ if(defined $sg);
+
+ return $res;
+ };
+
+sub unite {
+ my ($class,$other) = @_;
+
+ return
+ unless($other);
+
+ croak "Model '".$other."' is not instance of RDFStore::Model"
+ unless( (defined $other) && (ref($other)) &&
+ ($other->isa('RDFStore::Model')) );
+
+ croak "Models can not be united"
+ unless( ( $class->{Shared} == $class->{Shared} ) ||
+ ( $class->{rdfstore} == $other->{rdfstore} ) );
+
+ my $res = $class->create(); #EMPTY MODEL in-memory
+
+ $res->{Shared} = $class; # share storage (the other is sharing it anyway by definition :-)
+
+ my $iter = $class->elements->unite( $other->elements );
+
+ return
+ unless($iter);
+
+ $res->{query_iterator} = $iter->{iterator};
+
+ # set default context if any was set
+ my $sg = $class->getContext;
+ $res->setContext( $sg )
+ if(defined $sg);
+
+ return $res;
+ };
+
+sub complement {
+ my ($class) = @_;
+
+ my $res = $class->create(); #EMPTY MODEL in-memory
+
+ $res->{Shared} = $class; # share storage (the other is sharing it anyway by definition :-)
+
+ my $iter = $class->elements->complement;
+
+ return
+ unless($iter);
+
+ $res->{query_iterator} = $iter->{iterator};
+
+ # set default context if any was set
+ my $sg = $class->getContext;
+ $res->setContext( $sg )
+ if(defined $sg);
+
+ return $res;
+ };
+
+sub exor {
+ my ($class,$other) = @_;
+
+ return
+ unless($other);
+
+ croak "Model '".$other."' is not instance of RDFStore::Model"
+ unless( (defined $other) && (ref($other)) &&
+ ($other->isa('RDFStore::Model')) );
+
+ croak "EXOR can not be performed between the two given models"
+ unless( ( $class->{Shared} == $class->{Shared} ) ||
+ ( $class->{rdfstore} == $other->{rdfstore} ) );
+
+ my $res = $class->create(); #EMPTY MODEL in-memory
+
+ $res->{Shared} = $class; # share storage (the other is sharing it anyway by definition :-)
+
+ my $iter = $class->elements->exor( $other->elements ); # that easy :)
+
+ return
+ unless($iter);
+
+ $res->{query_iterator} = $iter->{iterator};
+
+ # set default context if any was set
+ my $sg = $class->getContext;
+ $res->setContext( $sg )
+ if(defined $sg);
+
+ return $res;
+ };
+
+#serialize the model/graph as string or to a filehandle using a specific syntax ("RDF/XML", "N-Triples")
+sub serialize {
+ my ($class, $fh, $syntax, $namespaces, $base ) = @_;
+
+ my $serializer;
+ if( (! $syntax ) ||
+ ( $syntax =~ m#RDF/XML#i) ) {
+ $serializer = new RDFStore::Serializer::RDFXML;
+ } elsif( $syntax =~ m/N-Triples/i) {
+ $serializer = new RDFStore::Serializer::NTriples;
+ } else {
+ croak "Unknown serialization syntax '$syntax'";
+ };
+
+ return
+ unless($serializer);
+
+ return $serializer->write( $class, $fh, $namespaces, $base );
+};
+
+sub getSerializer {
+ my ($class) = shift;
+
+ $class->getWriter(@_);
+ };
+
+sub getWriter {
+ my ($class, $syntax) = @_;
+
+ my $serializer;
+ if( (! $syntax ) ||
+ ( $syntax =~ m#RDF/XML#i) ) {
+ $serializer = new RDFStore::Serializer::RDFXML;
+ } elsif( $syntax =~ m/N-Triples/i) {
+ $serializer = new RDFStore::Serializer::NTriples;
+ } else {
+ croak "Unknown serialization syntax '$syntax'";
+ };
+
+ $serializer->{'model'} = $class; #not sure is correct - perhaps we really need to spell it out in write() method
+
+ return $serializer;
+ };
+
+sub getParser {
+ my ($class) = shift;
+
+ $class->getReader(@_);
+ };
+
+sub getReader {
+ my ($class, $syntax) = @_;
+
+ $class->{'GenidNumber'} = 0
+ unless(exists $class->{'GenidNumber'});
+
+ my $parser;
+ if( (! $syntax ) ||
+ ( $syntax =~ m#RDF/XML#i) ) {
+ $parser = new RDFStore::Parser::SiRPAC(
+ ErrorContext => 3,
+ Style => 'RDFStore::Parser::Styles::RDFStore::Model',
+ NodeFactory => $class->getNodeFactory,
+ Source => ($class->getSourceURI ) ? $class->getSourceURI : undef,
+ GenidNumber => $class->{'GenidNumber'},
+ 'style_options' => { 'store_options' => { 'sourceModel' => $class } } );
+ } elsif( $syntax =~ m/N-Triples/i) {
+ $parser = new RDFStore::Parser::NTriples(
+ ErrorContext => 3,
+ Style => 'RDFStore::Parser::Styles::RDFStore::Model',
+ NodeFactory => $class->getNodeFactory,
+ Source => ($class->getSourceURI ) ? $class->getSourceURI : undef,
+ GenidNumber => $class->{'GenidNumber'},
+ 'style_options' => { 'store_options' => { 'sourceModel' => $class } } );
+ } else {
+ croak "Unknown RDF syntax '$syntax'";
+ };
+
+ return $parser;
+ };
+
+# Copy shared statements across; we do not set any context for them here bacause the add() below will do it eventually using the default context. Shared/virtual models are there for efficiency
+# only and can be only generated by a find() or duplicate(); in the former case the context eventually is the context of the query while in the latter is the contexnt of the model (default one).
+# Those two other methods are setting/copying the right default context if necessary
+sub _copyOnWrite {
+ my($class) = @_;
+
+ return
+ unless( (exists $class->{Shared}) &&
+ (defined $class->{Shared}) );
+
+#print "Copying stuff across:\n";
+
+ my ($shares) = $class->elements;
+
+ #forget about being a query model if necessary :)
+ delete($class->{query});
+ if(exists $class->{query_iterator}) {
+ delete($class->{query_iterator});
+ };
+
+ #break the sharing
+ delete($class->{Shared});
+
+ my $ss;
+ for ( $ss = $shares->first;
+ $shares->hasnext;
+ $ss = $shares->next ) {
+ #print "\tcopying('".$ss->toString."')\n";
+ $class->add($ss); # what about context here in the cross-copy???
+ };
+
+#print "\nDONE!\n";
+};
+
+# simple front-end to RDFStore::Iterator using a the given nodeFactory
+package RDFStore::Model::Iterator;
+
+use vars qw ( $VERSION );
+use strict;
+
+$VERSION = '0.1';
+
+sub new {
+ my ($pkg,$factory,$iterator) = @_;
+
+ return
+ unless( (defined $iterator) &&
+ (ref($iterator)) &&
+ ($iterator->isa("RDFStore::Iterator")) &&
+ (defined $factory) &&
+ (ref($factory)) &&
+ ($factory->isa("RDFStore::NodeFactory")) );
+
+ return bless {
+ factory => $factory,
+ iterator => $iterator
+ },$pkg;
+ };
+
+sub size {
+ return $_[0]->{iterator}->size;
+ };
+
+sub duplicate {
+ return $_[0]->{iterator}->duplicate;
+ };
+
+sub hasnext {
+ return $_[0]->{iterator}->hasnext;
+ };
+
+sub remove {
+ return $_[0]->{iterator}->remove;
+ };
+
+sub intersect {
+ return
+ unless( (defined $_[1]) &&
+ (ref($_[1])) &&
+ ($_[1]->isa("RDFStore::Model::Iterator")) );
+
+ return new RDFStore::Model::Iterator( $_[0]->{factory},
+ $_[0]->{iterator}->intersect( $_[1]->{iterator} ) );
+ };
+
+sub unite {
+ return
+ unless( (defined $_[1]) &&
+ (ref($_[1])) &&
+ ($_[1]->isa("RDFStore::Model::Iterator")) );
+
+ return new RDFStore::Model::Iterator( $_[0]->{factory},
+ $_[0]->{iterator}->unite( $_[1]->{iterator} ) );
+ };
+
+sub subtract {
+ return
+ unless( (defined $_[1]) &&
+ (ref($_[1])) &&
+ ($_[1]->isa("RDFStore::Model::Iterator")) );
+
+ return new RDFStore::Model::Iterator( $_[0]->{factory},
+ $_[0]->{iterator}->subtract( $_[1]->{iterator} ) );
+ };
+
+sub complement {
+ return
+ unless( (defined $_[1]) &&
+ (ref($_[1])) &&
+ ($_[1]->isa("RDFStore::Model::Iterator")) );
+
+ return new RDFStore::Model::Iterator( $_[0]->{factory},
+ $_[0]->{iterator}->complement( $_[1]->{iterator} ) );
+ };
+
+sub exor {
+ return
+ unless( (defined $_[1]) &&
+ (ref($_[1])) &&
+ ($_[1]->isa("RDFStore::Model::Iterator")) );
+
+ return new RDFStore::Model::Iterator( $_[0]->{factory},
+ $_[0]->{iterator}->exor( $_[1]->{iterator} ) );
+ };
+
+sub next {
+ my ($st) = $_[0]->{iterator}->next;
+
+ return
+ unless($st);
+
+ return $_[0]->{factory}->createStatement(
+ ( $st->subject->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $st->subject->toString ) :
+ $_[0]->{factory}->createResource( $st->subject->toString ),
+ ( $st->predicate->isbNode ) ? # I know that is not possible but we allow it anyway ;-/
+ $_[0]->{factory}->createAnonymousResource( $st->predicate->toString ) :
+ $_[0]->{factory}->createResource( $st->predicate->toString ),
+ ( $st->object->isa("RDFStore::Literal") ) ?
+ $_[0]->{factory}->createLiteral( $st->object->getLabel,
+ $st->object->getParseType,
+ $st->object->getLang,
+ $st->object->getDataType ) :
+ ( $st->object->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $st->object->toString ) :
+ $_[0]->{factory}->createResource( $st->object->toString ),
+ ( $st->context ) ? ( $st->context->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $st->context->toString ) :
+ $_[0]->{factory}->createResource( $st->context->toString ) : undef );
+ };
+
+sub next_subject {
+ my ($n) = $_[0]->{iterator}->next_subject;
+
+ return
+ unless($n);
+
+ return ( $n->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $n->toString ) :
+ $_[0]->{factory}->createResource( $n->toString );
+ };
+
+sub next_predicate {
+ my ($n) = $_[0]->{iterator}->next_predicate;
+
+ return
+ unless($n);
+
+ return ( $n->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $n->toString ) :
+ $_[0]->{factory}->createResource( $n->toString );
+ };
+
+sub next_object {
+ my ($n) = $_[0]->{iterator}->next_object;
+
+ return
+ unless($n);
+
+ return ( $n->isa("RDFStore::Literal") ) ?
+ $_[0]->{factory}->createLiteral( $n->getLabel,
+ $n->getParseType,
+ $n->getLang,
+ $n->getDataType ) :
+ ( $n->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $n->toString ) :
+ $_[0]->{factory}->createResource( $n->toString );
+ };
+
+sub next_context {
+ my ($n) = $_[0]->{iterator}->next_context;
+
+ return
+ unless($n);
+
+ return ( $n->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $n->toString ) :
+ $_[0]->{factory}->createResource( $n->toString );
+ };
+
+sub current {
+ my ($st) = $_[0]->{iterator}->current;
+
+ return
+ unless($st);
+
+ return $_[0]->{factory}->createStatement(
+ ( $st->subject->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $st->subject->toString ) :
+ $_[0]->{factory}->createResource( $st->subject->toString ),
+ ( $st->predicate->isbNode ) ? # I know that is not possible but we allow it anyway ;-/
+ $_[0]->{factory}->createAnonymousResource( $st->predicate->toString ) :
+ $_[0]->{factory}->createResource( $st->predicate->toString ),
+ ( $st->object->isa("RDFStore::Literal") ) ?
+ $_[0]->{factory}->createLiteral( $st->object->getLabel,
+ $st->object->getParseType,
+ $st->object->getLang,
+ $st->object->getDataType ) :
+ ( $st->object->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $st->object->toString ) :
+ $_[0]->{factory}->createResource( $st->object->toString ),
+ ( $st->context ) ? ( $st->context->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $st->context->toString ) :
+ $_[0]->{factory}->createResource( $st->context->toString ) : undef );
+ };
+
+sub current_subject {
+ my ($n) = $_[0]->{iterator}->current_subject;
+
+ return
+ unless($n);
+
+ return ( $n->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $n->toString ) :
+ $_[0]->{factory}->createResource( $n->toString );
+ };
+
+sub current_predicate {
+ my ($n) = $_[0]->{iterator}->current_predicate;
+
+ return
+ unless($n);
+
+ return ( $n->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $n->toString ) :
+ $_[0]->{factory}->createResource( $n->toString );
+ };
+
+sub current_object {
+ my ($n) = $_[0]->{iterator}->current_object;
+
+ return
+ unless($n);
+
+ return ( $n->isa("RDFStore::Literal") ) ?
+ $_[0]->{factory}->createLiteral( $n->getLabel,
+ $n->getParseType,
+ $n->getLang,
+ $n->getDataType ) :
+ ( $n->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $n->toString ) :
+ $_[0]->{factory}->createResource( $n->toString );
+ };
+
+sub current_context {
+ my ($n) = $_[0]->{iterator}->current_context;
+
+ return
+ unless($n);
+
+ return ( $n->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $n->toString ) :
+ $_[0]->{factory}->createResource( $n->toString );
+ };
+
+sub first {
+ my ($st) = $_[0]->{iterator}->first;
+
+ return
+ unless($st);
+
+ return $_[0]->{factory}->createStatement(
+ ( $st->subject->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $st->subject->toString ) :
+ $_[0]->{factory}->createResource( $st->subject->toString ),
+ ( $st->predicate->isbNode ) ? # I know that is not possible but we allow it anyway ;-/
+ $_[0]->{factory}->createAnonymousResource( $st->predicate->toString ) :
+ $_[0]->{factory}->createResource( $st->predicate->toString ),
+ ( $st->object->isa("RDFStore::Literal") ) ?
+ $_[0]->{factory}->createLiteral( $st->object->getLabel,
+ $st->object->getParseType,
+ $st->object->getLang,
+ $st->object->getDataType ) :
+ ( $st->object->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $st->object->toString ) :
+ $_[0]->{factory}->createResource( $st->object->toString ),
+ ( $st->context ) ? ( $st->context->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $st->context->toString ) :
+ $_[0]->{factory}->createResource( $st->context->toString ) : undef );
+ };
+
+sub first_subject {
+ my ($n) = $_[0]->{iterator}->first_subject;
+
+ return
+ unless($n);
+
+ return ( $n->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $n->toString ) :
+ $_[0]->{factory}->createResource( $n->toString );
+ };
+
+sub first_predicate {
+ my ($n) = $_[0]->{iterator}->first_predicate;
+
+ return
+ unless($n);
+
+ return ( $n->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $n->toString ) :
+ $_[0]->{factory}->createResource( $n->toString );
+ };
+
+sub first_object {
+ my ($n) = $_[0]->{iterator}->first_object;
+
+ return
+ unless($n);
+
+ return ( $n->isa("RDFStore::Literal") ) ?
+ $_[0]->{factory}->createLiteral( $n->getLabel,
+ $n->getParseType,
+ $n->getLang,
+ $n->getDataType ) :
+ ( $n->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $n->toString ) :
+ $_[0]->{factory}->createResource( $n->toString );
+ };
+
+sub first_context {
+ my ($n) = $_[0]->{iterator}->first_context;
+
+ return
+ unless($n);
+
+ return ( $n->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $n->toString ) :
+ $_[0]->{factory}->createResource( $n->toString );
+ };
+
+sub each {
+ my ($st) = $_[0]->{iterator}->each;
+
+ return
+ unless($st);
+
+ return $_[0]->{factory}->createStatement(
+ ( $st->subject->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $st->subject->toString ) :
+ $_[0]->{factory}->createResource( $st->subject->toString ),
+ ( $st->predicate->isbNode ) ? # I know that is not possible but we allow it anyway ;-/
+ $_[0]->{factory}->createAnonymousResource( $st->predicate->toString ) :
+ $_[0]->{factory}->createResource( $st->predicate->toString ),
+ ( $st->object->isa("RDFStore::Literal") ) ?
+ $_[0]->{factory}->createLiteral( $st->object->getLabel,
+ $st->object->getParseType,
+ $st->object->getLang,
+ $st->object->getDataType ) :
+ ( $st->object->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $st->object->toString ) :
+ $_[0]->{factory}->createResource( $st->object->toString ),
+ ( $st->context ) ? ( $st->context->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $st->context->toString ) :
+ $_[0]->{factory}->createResource( $st->context->toString ) : undef );
+ };
+
+sub each_subject {
+ my ($n) = $_[0]->{iterator}->each_subject;
+
+ return
+ unless($n);
+
+ return ( $n->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $n->toString ) :
+ $_[0]->{factory}->createResource( $n->toString );
+ };
+
+sub each_predicate {
+ my ($n) = $_[0]->{iterator}->each_predicate;
+
+ return
+ unless($n);
+
+ return ( $n->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $n->toString ) :
+ $_[0]->{factory}->createResource( $n->toString );
+ };
+
+sub each_object {
+ my ($n) = $_[0]->{iterator}->each_object;
+
+ return
+ unless($n);
+
+ return ( $n->isa("RDFStore::Literal") ) ?
+ $_[0]->{factory}->createLiteral( $n->getLabel,
+ $n->getParseType,
+ $n->getLang,
+ $n->getDataType ) :
+ ( $n->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $n->toString ) :
+ $_[0]->{factory}->createResource( $n->toString );
+ };
+
+sub each_context {
+ my ($n) = $_[0]->{iterator}->each_context;
+
+ return
+ unless($n);
+
+ return ( $n->isbNode ) ?
+ $_[0]->{factory}->createAnonymousResource( $n->toString ) :
+ $_[0]->{factory}->createResource( $n->toString );
+ };
+
+1;
+};
+
+__END__
+
+=head1 NAME
+
+RDFStore::Model - An implementation of the Model RDF API using tied hashes and implementing free-text search on literals
+
+=head1 SYNOPSIS
+
+ use RDFStore::NodeFactory;
+ my $factory= new RDFStore::NodeFactory();
+ my $statement = $factory->createStatement(
+ $factory->createResource('http://perl.org'),
+ $factory->createResource('http://iscool.org/schema/1.0/','label'),
+ $factory->createLiteral('Cool Web site')
+ );
+ my $statement1 = $factory->createStatement(
+ $factory->createResource("http://www.altavista.com"),
+ $factory->createResource("http://pen.jrc.it/schema/1.0/','author'),
+ $factory->createLiteral("Who? :-)")
+ );
+
+ my $statement2 = $factory->createStatement(
+ $factory->createUniqueResource(),
+ $factory->createUniqueResource(),
+ $factory->createLiteral("")
+ );
+
+ use RDFStore::Model;
+ my $model = new RDFStore::Model( Name => 'store', FreeText => 1 );
+
+ $model->add($statement);
+ $model->add($statement1);
+ $model->add($statement2);
+ my $model1 = $model->duplicate();
+
+ print $model1->getDigest->equals( $model1->getDigest );
+ print $model1->getDigest->hashCode;
+
+ my $found = $model->find($statement2->subject,undef,undef);
+ my $found1 = $model->find(undef,undef,undef,undef,'Cool'); #free-text search on literals :)
+
+ #get Statements
+ foreach ( @{$found->elements} ) {
+ print $_->getLabel(),"\n";
+ };
+
+ #or faster
+ my $fetch;
+ foreach ( @{$found->elements} ) {
+ my $fetch=$_; #avoid too many fetches from RDFStore::Model::Statements
+ print $fetch->getLabel(),"\n";
+ };
+
+ #or
+ my($statements)=$found1->elements;
+ for ( 0..$#{$statements} ) {
+ print $statements->[$_]->getLabel(),"\n";
+ };
+
+ #get RDFNodes
+ foreach ( keys %{$found->elements}) {
+ print $found->elements->{$_}->getLabel(),"\n";
+ };
+
+ # set operations
+ my $set = new RDFStore::Model( Name => 'setmodel' );
+
+ $set=$set->interset($other_model);
+ $set=$set->unite($other_model);
+ $set=$set->subtract($other_model);
+
+=head1 DESCRIPTION
+
+An RDFStore::Model implementation using RDFStore(3) to store triplets.
+
+=head1 CONSTRUCTORS
+
+The following methods construct/tie RDFStore::Model storages and objects:
+
+=item $model = new RDFStore::Model( %whateveryoulikeit );
+
+Create an new RDFStore::Model object and tie up the RDFStore(3). The %whateveryoulikeit hash contains a set of configuration options about how and where store actual data.
+
+Possible additional options are the following:
+
+=over 4
+
+=item Name
+
+This is a label used to identify a B<Persistent> storage by name. It might correspond to a physical file system directory containing the indexes DBs. By default if no B<Name> option is given the storage is assumed to be B<in-memory> (e.g. RDFStore::Storage::find method return result sets as in-memory models by default unless specified differently). For local persistent storages a directory named liek this option is created in the current working directory with mode 0666)
+
+=item Sync
+
+Sync the RDFStore::Model with the underling Data::MagciTie GDS after each add() or remove().
+
+=item FreeText
+
+Enable free text searching on literals over a model (see B<find>)
+
+=head1 SEE ALSO
+
+Digest(3) RDFStore(3) RDFStore::Digest::Digestable(3) RDFStore::Digest(3) RDFStore::RDFNode(3) RDFStore::Resource(3)
+
+=head1 AUTHOR
+
+ Alberto Reggiori <ar...@webweaving.org>
Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/RDFStore/NodeFactory.pm
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/RDFStore/NodeFactory.pm?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/RDFStore/NodeFactory.pm (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/lib/RDFStore/NodeFactory.pm Fri Apr 13 01:56:01 2007
@@ -0,0 +1,314 @@
+# *
+# * Copyright (c) 2000-2006 Alberto Reggiori <ar...@webweaving.org>
+# * Dirk-Willem van Gulik <di...@webweaving.org>
+# *
+# * NOTICE
+# *
+# * This product is distributed under a BSD/ASF like license as described in the 'LICENSE'
+# * file you should have received together with this source code. If you did not get a
+# * a copy of such a license agreement you can pick up one at:
+# *
+# * http://rdfstore.sourceforge.net/LICENSE
+# *
+# * Changes:
+# * version 0.1 - 2000/11/03 at 04:30 CEST
+# * version 0.2
+# * - modified createResource() method accordingly to rdf-api-2000-10-30
+# * version 0.4
+# * - changed way to return undef in subroutines
+# * - implemented createOrdinal()
+# * version 0.41
+# * - added anonymous resource support via createAnonymousResource() and createbNode() - see also RDFStore::Resource(3)
+# * - added statements reification support via createReifiedStatement() - see also RDFStore::Statement(3)
+# * - updated accordingly to new RDFStore API
+# * - added createNTriple() method
+# * version 0.42
+# * - fixed bNodes identifers generation
+# *
+
+package RDFStore::NodeFactory;
+{
+use vars qw ($VERSION);
+use strict;
+
+$VERSION = '0.42';
+
+use Carp;
+use RDFStore::Literal;
+use RDFStore::Resource;
+use RDFStore::Statement;
+use RDFStore::Util::Digest;
+
+sub new {
+ my ( $pkg, $nodesCounter, $bnodesCounter, $timestamp, $rand_seed ) = @_;
+
+ $nodesCounter = 0
+ unless($nodesCounter);
+ $bnodesCounter = 0
+ unless($bnodesCounter);
+ $timestamp = time()
+ unless($timestamp);
+ $rand_seed = unpack("H*", rand())
+ unless($rand_seed);
+
+ bless {
+ 'nodesCounter' => $nodesCounter,
+ 'bnodesCounter' => $bnodesCounter,
+ 'timestamp' => $timestamp,
+ 'rand_seed' => $rand_seed
+ }, $pkg;
+ };
+
+# Creates a resource from a URI or from namespace and local name
+sub createResource {
+ if(defined $_[2]) {
+ return new RDFStore::Resource($_[1],$_[2]) or
+ return;
+ } else {
+ return ($_[1]) ? new RDFStore::Resource($_[1]) : undef;
+ };
+ };
+
+sub createAnonymousResource {
+ if(defined $_[1]) {
+ return new RDFStore::Resource($_[1], undef, 1);
+ } else {
+ # try to generate system/run wide unique ID i.e. 'S' + unpack("H*", rand()) + 'P' + $$ + 'T' + time() + 'N' + GenidNumber
+ return new RDFStore::Resource(
+ 'rdfnodeIDgenidrdfstore' .
+ 'S'.$_[0]->{'rand_seed'} .
+ 'P'. $$.
+ 'T'. $_[0]->{'timestamp'} .
+ 'N'. $_[0]->{bnodesCounter}++, undef, 1 );
+ };
+ };
+
+sub createbNode {
+ my ($class) = shift;
+
+ return $class->createAnonymousResource(@_);
+ };
+
+sub createLiteral {
+ my ($class) = shift;
+
+ return new RDFStore::Literal(@_);
+ };
+
+sub createStatement {
+ return ( (defined $_[1]) &&
+ (defined $_[2]) &&
+ (defined $_[3]) ) ? new RDFStore::Statement($_[1], $_[2], $_[3], (defined $_[4]) ? $_[4] : undef ) :
+ undef;
+ };
+
+sub createReifiedStatement {
+ return ( (defined $_[1]) &&
+ (defined $_[2]) &&
+ (defined $_[3]) ) ?
+ new RDFStore::Statement( $_[1], $_[2], $_[3],
+ ( (defined $_[4]) ? $_[4] : undef ), 1,
+ ( (defined $_[5]) ? $_[5] : undef ) ) : undef;
+ };
+
+# Creates a resource with a unique ID
+sub createUniqueResource {
+ # try to generate system/run wide unique ID i.e. 'S' + unpack("H*", rand()) + 'P' + $$ + 'T' + time() + 'N' + IdNumber
+ return new RDFStore::Resource(
+ 'rdfresourcerdfstore' .
+ 'S'.$_[0]->{'rand_seed'} .
+ 'P'. $$.
+ 'T'. $_[0]->{'timestamp'} .
+ 'N'. $_[0]->{nodesCounter}++ );
+ };
+
+# Creates an ordinal property (rdf:li, rdf:_N)
+sub createOrdinal {
+ my ($class,$i) = @_;
+
+ if($i < 1) {
+ croak "Attempt to construct invalid ordinal resource";
+ } else {
+ return $class->createResource("http://www.w3.org/1999/02/22-rdf-syntax-ns#", "_" . $i);
+ };
+ };
+
+# see http://www.w3.org/TR/rdf-testcases/#ntriples and http://robustai.net/sailor/grammar/Quads.html
+sub createNTriple {
+ my ($class, $ntriple) = @_;
+
+ # some basic parsing - see http://aspn.activestate.com/ASPN/Mail/Message/787168
+ chomp( $ntriple );
+ $ntriple =~ s/^[\x20\x09]+//; # remove leading white space
+ $ntriple =~ s/[\x20\x09]+$//; # remove trailing white space
+
+ if ($ntriple =~ m/[^\x20-\x7e\x0d\x0a\x09]/) {
+ warn 'Invalid character(s) found';
+ return undef;
+ };
+
+ unless ($ntriple =~ s/\.$//) {
+ warn 'Syntax error: missing trailing full stop';
+ return undef;
+ };
+
+ my ($subject, $predicate, $object, $context );
+
+ # parse subject
+ if ($ntriple =~ s/^<([^>]*)>[\x20\x09]+//) {
+ # uriref
+ $subject = $class->createResource( $1 );
+ } elsif ($ntriple =~ s/^_:([A-Za-z][A-Za-z0-9]*)[\x20\x09]+//) {
+ # bNode
+ $subject = $class->createbNode( $1 );
+ } else {
+ warn 'Syntax error in <subject> token';
+ return undef;
+ };
+
+ # parse predicate
+ if ($ntriple =~ s/^<([^>]*)>[\x20\x09]+//) {
+ # uriref
+ $predicate = $class->createResource( $1 );
+ } else {
+ warn 'Syntax error in <predicate> token';
+ return undef;
+ };
+
+ # parse object
+ if ($ntriple =~ s/^<([^>]*)>[\x20\x09]+//) {
+ # uriref
+ $object = $class->createResource( $1 );
+ } elsif ($ntriple =~ s/^_:([A-Za-z][A-Za-z0-9]*)[\x20\x09]+//) {
+ # bNode
+ $object = $class->createbNode( $1 );
+ } elsif ($ntriple =~ s/"([^"]*)"\@([a-z0-9]+(-[a-z0-9]+)?)\^\^<([^>]*)>[\x20\x09]+//) {
+ # literal
+ if ( $4 eq 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral' ) {
+ #parseType='Literal'
+ $object = $class->createLiteral( $1, 1, $2, $4 );
+ } else {
+ $object = $class->createLiteral( $1, undef, $2, $4 );
+ };
+ } elsif ($ntriple =~ s/"([^"]*)"\^\^<([^>]*)>[\x20\x09]+//) {
+ # literal
+ if ( $2 eq 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral' ) {
+ #parseType='Literal'
+ $object = $class->createLiteral( $1, 1, undef, $2 );
+ } else {
+ $object = $class->createLiteral( $1, undef, undef, $2 );
+ };
+ } elsif ($ntriple =~ s/"([^"]*)"\@([a-z0-9]+(-[a-z0-9]+)?)[\x20\x09]+//) {
+ # literal
+ $object = $class->createLiteral( $1, undef, $2 );
+ } elsif ($ntriple =~ s/"([^"]*)"[\x20\x09]+//) {
+ # literal
+ $object = $class->createLiteral( $1 );
+ } else {
+ warn 'Syntax error in <object> token';
+ return undef;
+ };
+
+ if ( length($ntriple) ) {
+ # parse context (Quads actually see http://robustai.net/sailor/grammar/Quads.html)
+ if ($ntriple =~ s/^<([^>]*)>[\x20\x09]+//) {
+ # uriref
+ $context = $class->createResource( $1 );
+ } elsif ($ntriple =~ s/^_:([A-Za-z][A-Za-z0-9]*)[\x20\x09]+//) {
+ # bNode
+ $context = $class->createbNode( $1 );
+ } else {
+ warn 'Trash found after <object> token'; # should really say 'Syntax error in <context> token' :-)
+ return undef;
+ };
+ };
+
+ return $class->createStatement( $subject, $predicate, $object, $context );
+};
+
+1;
+};
+
+__END__
+
+=head1 NAME
+
+RDFStore::NodeFactory - An RDF node factory implementation
+
+=head1 SYNOPSIS
+
+ use RDFStore::NodeFactory;
+ my $factory = new RDFStore::NodeFactory();
+ my $statement = $factory->createStatement(
+ $factory->createResource("http://pen.com"),
+ $factory->createResource("http://purl.org/schema/1.0#author"),
+ $factory->createLiteral("Peter Pan")
+ );
+ my $reified_statement = $factory->createReifiedStatement(
+ $factory->createResource("http://pen.com"),
+ $factory->createResource("http://purl.org/schema/1.0#author"),
+ $factory->createLiteral("Lady Oscar")
+ );
+
+
+=head1 DESCRIPTION
+
+An RDFStore::NodeFactory implementation using RDFStore::RDFNode, RDFStore::Resource and RDFStore::Literal
+
+=head1 METHODS
+
+=over 4
+
+=item new
+
+This is a class method, the constructor for RDFStore::NodeFactory.
+
+=item createResource( LOCALNAME_NAMESPACE [, LOCALNAME ] )
+
+Create a new RDFStore::Resource. If the method is called with a single perl scalar as parameter a new RDF Resource is created with the string passed as indentifier (LOCALNAME); a fully qualified RDF resource can be constructed by invoching the constructor with B<two> paramter s where the former is the NAMESPACE and the latter is the LOCALNAME. By RDF definition we assume that B<LOCALNAME can not be undefined>. If LOCALNAME is a perl reference the new Resource is flagged as anonymous-resource or bNode.
+
+bNodes can also be created using the B<createbNode> or B<createAnonymousResource> methods below
+
+=item createAnonymousResource( LOCALNAME_NAMESPACE [, LOCALNAME ] )
+
+Create a new anonymous RDFStore::Resource like in the B<createResource> method above but the method is setting the RDFStore::Resource(3) internal bNode flag.
+
+=item createbNode( LOCALNAME_NAMESPACE [, LOCALNAME ] )
+
+Create a new anonymous RDFStore::Resource like in the B<createResource> method above but the method is setting the RDFStore::Resource(3) internal bNode flag.
+
+=item createLiteral( LITERAL )
+
+Create a new RDFStore::Literal. The only parameter passed is either a plain perl scalar (LITERAL) - see RDFStore::Literal(3)
+
+=item createStatement( SUBJECT, PREDICATE, OBJECT )
+
+Create a new RDFStore::Statement. SUBJECT and PREDICATE must be two RDFStore::Resource while OBJECT is RDFStore::RDFNode
+
+=item createUniqueResource
+
+Creates a new RDFStore::Resource with a unique ID using a random seed.
+
+=item createOrdinal( INTEGER )
+
+Creates a new RDFStore::Resource ordinal property (rdf:li, rdf:_N). The only parameter INTEGER is the scalar number to set the property to.
+
+=head1 ABOUT RDF
+
+ http://www.w3.org/TR/rdf-primer/
+
+ http://www.w3.org/TR/rdf-mt
+
+ http://www.w3.org/TR/rdf-syntax-grammar/
+
+ http://www.w3.org/TR/rdf-schema/
+
+ http://www.w3.org/TR/1999/REC-rdf-syntax-19990222 (obsolete)
+
+=head1 SEE ALSO
+
+RDFStore::RDFNode(3) RDFStore::Resource(3) RDFStore::Literal(3) RDFStore(3)
+
+=head1 AUTHOR
+
+ Alberto Reggiori <ar...@webweaving.org>