package MooseX::Semantic::Role::RdfImportAll; use Moose::Role; use namespace::autoclean; use RDF::Trine::Namespace qw/rdf/; use MooseX::Semantic::Types qw(ArrayOfTrineResources); use Try::Tiny; use Data::Dumper; with( 'MooseX::Semantic::Role::RdfImport' ); =head1 NAME MooseX::Semantic::Role::RdfImportAll - Import all resources from a RDF source =head1 SYNOPSIS # multiple_persons.ttl @prefix foaf: . @prefix schema: . a foaf:Person ; foaf:name "Alice" . a schema:Person ; foaf:name "Bob" . # My/Model/Person.pm package My::Model::Person; use Moose; with qw( MooseX::Semantic::Role::RdfImportAll MooseX::Semantic::Role::WithRdfType ); __PACKAGE__->rdf_type([qw{http://xmlns.com/foaf/0.1/Person http://schema.org/Person}]); has name => ( is => 'rw', traits => ['Semantic'], uri => 'http://xmlns.com/foaf/0.1/name', uri_reader => [qw(http://schema.org/name)] ); ... # your script my $model = RDF::Trine::Model->new; RDF::Trine::Parser::Turtle->new->parse_file_into_model( 'http://example.com/', 'multiple_persons.ttl', $model ); my @people = My::Model::Person->import_all_from_model($model); print $people[0]->name; # prints 'Alice' print $people[1]->name; # prints 'Bob' =head1 DESCRIPTION =head1 METHODS =cut =head2 import_all C For C<%opts> see L below. =cut sub import_all { my $class = shift; my %opts = @_; my $model = delete $opts{model}; if ($model) { return $class->import_all_from_model( $model, %opts ); } my $uris = delete $opts{uri}; $uris = delete( $opts{uris} ) unless $uris; if ( $uris ) { return $class->import_all_from_web( $uris, %opts ); } confess "Must specify either 'uri' or 'model' to 'import_all'"; } =head2 import_all_from_model C Imports all resources from C<$model>. For C<%opts> see L below. =cut sub import_all_from_model { my ($class, $model, %opts ) = @_; my @rdf_types = $class->_get_rdf_types_from_opts_or_class(%opts); my %resources; # use hash to uniquify results. foreach my $type (@rdf_types) { # warn Dumper $type; $model->subjects($rdf->type, $type)->each(sub { my $r = shift; $resources{ $r } = $r; }); } my @return; foreach my $r (values %resources) { my $R; # Skip over resources which throw exceptions. # Usually they are missing a required property. try { $R = $class->new_from_model($model, $r); } catch { # warn $r; # warn substr( $_, 0, 20); }; # skip undefined resources next unless defined $R; # skip blank nodes if $opts{skip_blank} is set next if ($opts{skip_blank} && $R->rdf_about->is_blank); push @return, $R; } @return; } =head2 import_all_from_web C TODO For C<%opts> see L below. =cut sub import_all_from_web { my ($class, $opt_uris, %opts) = @_; my @uris = @{ $opt_uris }; confess "Must specify at least one 'uri' for import_all_from_web." unless scalar @uris; my @rdf_types = $class->_get_rdf_types_from_opts_or_class(%opts); my $model = RDF::Trine::Model->temporary_model; RDF::Trine::Parser->parse_url_into_model($_, $model) foreach @uris; return $class->import_all_from_model($model, %opts); } sub _get_rdf_types_from_opts_or_class { my ($class, %opts) = @_; my $rdf_types; if ($opts{rdf_type}) { $rdf_types = ArrayOfTrineResources->coerce( $opts{rdf_type} ); } else { confess("Class $class has no associated RDF types and no 'rdf_type' argument was specified.") unless $class->can('rdf_type') && scalar $class->list_rdf_types; $rdf_types = [$class->list_rdf_types]; } # warn Dumper $rdf_types; return @{$rdf_types}; } no Moose; 1; =head1 IMPORT OPTIONS =over 4 =item C Additional rdf:types =item C The model to import from =item C =item C An array reference of URIs to import =item C If set to true, blank nodes (i.e. resources without a URI) are skipped. =back =head1 AUTHOR Konstantin Baierer () =head1 SEE ALSO =over 4 =item L =back =cut =head1 LICENCE AND COPYRIGHT This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See perldoc perlartistic. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.