File Coverage

blib/lib/RDF/Closure.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package RDF::Closure;
2              
3 1     1   32793 use 5.008;
  1         5  
  1         42  
4 1     1   5 use strict;
  1         2  
  1         35  
5 1     1   1264 use utf8;
  1         17  
  1         6  
6              
7 1     1   628 use RDF::Trine::Namespace qw[RDF RDFS OWL XSD];
  0            
  0            
8             use RDF::Trine::Parser::OwlFn qw[];
9             use RDF::Closure::Engine qw[];
10             use RDF::Closure::Model qw[];
11             use Scalar::Util qw[];
12              
13             eval { require RDF::Trine };
14             our @ISA = qw(RDF::Trine);
15              
16             use constant FLT_NONRDF => 1;
17             use constant FLT_BORING => 2;
18              
19             our $VERSION = '0.001';
20              
21             our @EXPORT_OK;
22             BEGIN
23             {
24             @EXPORT_OK = (@RDF::Trine::EXPORT_OK, qw[mk_filter FLT_NONRDF FLT_BORING $RDF $RDFS $OWL $XSD]);
25             }
26              
27             sub mk_filter
28             {
29             my ($conditions, $boring_contexts) = @_;
30            
31             $boring_contexts = [$boring_contexts] unless ref $boring_contexts eq 'ARRAY';
32            
33             return sub
34             {
35             my ($st) = @_;
36            
37             if ($conditions & FLT_NONRDF)
38             {
39             return 0 unless $st->rdf_compatible;
40             }
41            
42             return 0 if grep { $st->context->equal($_) } @$boring_contexts;
43            
44             if ($conditions & FLT_BORING)
45             {
46             return 0
47             if $st->subject->equal($st->object)
48             && {
49             $OWL->sameAs->uri => 1,
50             $OWL->equivalentProperty->uri => 1,
51             $OWL->equivalentClass->uri => 1,
52             $RDFS->subPropertyOf->uri => 1,
53             $RDFS->subClassOf->uri => 1,
54             }->{$st->predicate->uri};
55            
56             my @nodes = $st->nodes;
57             foreach my $node (@nodes[0..2])
58             {
59             return 1
60             unless in_namespace($node, $RDF)
61             || in_namespace($node, $RDFS)
62             || in_namespace($node, $OWL)
63             || in_namespace($node, $XSD);
64             }
65             return 0;
66             }
67            
68             return 1;
69             };
70             }
71              
72             sub in_namespace
73             {
74             my ($node, $ns) = @_;
75            
76             return 0
77             if Scalar::Util::blessed($node)
78             && !$node->is_resource;
79            
80             my $ns_str = $ns->uri('')->uri;
81             my $node_substr = substr($node->uri, 0, length $ns_str);
82            
83             return ($node_substr eq $ns_str);
84             }
85              
86             1;
87              
88             =head1 NAME
89              
90             RDF::Closure - pure Perl RDF inferencing
91              
92             =head1 SYNOPSIS
93              
94             use RDF::Trine::Iterator qw[sgrep];
95             use RDF::Closure qw[iri mk_filter FLT_NONRDF FLT_BORING];
96            
97             my $data = iri('http://bloggs.example.com/foaf.rdf');
98             my $foaf = iri('http://xmlns.com/foaf/0.1/index.rdf');
99            
100             my $model = RDF::Trine::Model->temporary_model;
101             my $p = 'RDF::Trine::Parser';
102             $p->parse_url_into_model($data->uri, $model, context => $data->uri);
103             $p->parse_url_into_model($foaf->uri, $model, context => $foaf->uri);
104            
105             my $cl = RDF::Closure::Engine->new('rdfs', $model);
106             $cl->closure;
107            
108             my $filter = mk_filter(FLT_NONRDF|FLT_BORING, [$foaf]);
109             my $output = &sgrep($filter, $model->as_stream);
110            
111             print RDF::Trine::Serializer
112             ->new('RDFXML')
113             ->serialize_iterator_to_string($output);
114              
115             =head1 DESCRIPTION
116              
117             This distribution is a pure Perl RDF inference engine designed as an add-in
118             for L<RDF::Trine>. It is largely a port of Ivan Herman's Python RDFClosure
119             library, though there has been some restructuing, and there are a few extras
120             thrown in.
121              
122             Where one of the Perl modules has a direct equivalent in Ivan's library,
123             this is noted in the POD.
124              
125             =head2 Functions
126              
127             This package inherits from L<RDF::Trine> and exports the same functions,
128             plus:
129              
130             =over
131              
132             =item * C<< mk_filter($basic_filters, $ignore_contexts) >>
133              
134             Creates a filter (coderef) suitable for use with C<sgrep> from
135             L<RDF::Trine::Iterator>.
136              
137             C<$basic_filters> is an integer which can be assembled by bitwise-OR-ing
138             the constants C<FLT_NONRDF> and C<FLT_BORING>.
139              
140             C<$ignore_contexts> is an arrayref of L<RDF::Trine::Node> objects, each
141             of which represents a context that should be filtered out.
142              
143             use RDF::Trine::Iterator qw[sgrep];
144             use RDF::Closure qw[iri mk_filter FLT_NONRDF FLT_BORING];
145            
146             my $foaf = iri('http://xmlns.com/foaf/0.1/index.rdf');
147             my $filter = mk_filter(FLT_NONRDF|FLT_BORING, [$foaf]);
148            
149             my $remaining = &sgrep($filter, $model->as_stream);
150            
151             # $remaining is now an iterator which will return all triples
152             # from $model except: those in the FOAF named graph, those which
153             # are non-RDF (e.g. literal subject) and those which are boring.
154              
155             Which triples are boring? Any triple of the form { ?x owl:sameAs ?x .},
156             { ?x owl:equivalentProperty ?x .}, { ?x owl:equivalentClass ?x .},
157             { ?x rdfs:subPropertyOf ?x .} or { ?x rdfs:subClassOf ?x .} is boring
158             (i.e. where these statements have the same term in subject and object
159             position). Any triple where the subject, predicate and object nodes are
160             all in the RDF, RDFS, OWL or XSD namespaces is boring. Other triples are
161             not boring.
162              
163             =back
164              
165             For convenience, C<RDF::Closure> also exports variables called C<$RDF>,
166             C<$RDFS>, C<$OWL> and C<$XSD> which are L<RDF::Trine::Namespace> objects.
167              
168             =head1 SEE ALSO
169              
170             L<RDF::Closure::Engine>,
171             L<RDF::Closure::Model>,
172             L<RDF::Trine::Parser::OwlFn>.
173              
174             L<RDF::Trine>,
175             L<RDF::Query>.
176              
177             L<http://www.perlrdf.org/>.
178              
179             L<http://www.ivan-herman.net/Misc/2008/owlrl/>.
180              
181             =head1 AUTHOR
182              
183             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
184              
185             =head1 COPYRIGHT
186              
187             Copyright 2011-2012 Toby Inkster
188              
189             This library is free software; you can redistribute it and/or modify it
190             under any of the following licences:
191              
192             =over
193              
194             =item * The Artistic License 1.0 L<http://www.perlfoundation.org/artistic_license_1_0>.
195              
196             =item * The GNU General Public License Version 1 L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>,
197             or (at your option) any later version.
198              
199             =item * The W3C Software Notice and License L<http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231>.
200              
201             =item * The Clarified Artistic License L<http://www.ncftp.com/ncftp/doc/LICENSE.txt>.
202              
203             =back
204              
205             =head1 DISCLAIMER OF WARRANTIES
206              
207             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
208             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
209             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
210              
211             =cut
212