line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# RDF::Trine::Model |
2
|
|
|
|
|
|
|
# ----------------------------------------------------------------------------- |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
=head1 NAME |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
RDF::Trine::Model - Model class |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
=head1 VERSION |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
This document describes RDF::Trine::Model version 1.018 |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 METHODS |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=over 4 |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=cut |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
package RDF::Trine::Model; |
19
|
|
|
|
|
|
|
|
20
|
68
|
|
|
68
|
|
405
|
use strict; |
|
68
|
|
|
|
|
148
|
|
|
68
|
|
|
|
|
1565
|
|
21
|
68
|
|
|
68
|
|
313
|
use warnings; |
|
68
|
|
|
|
|
152
|
|
|
68
|
|
|
|
|
1509
|
|
22
|
68
|
|
|
68
|
|
300
|
no warnings 'redefine'; |
|
68
|
|
|
|
|
139
|
|
|
68
|
|
|
|
|
2612
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
our ($VERSION); |
25
|
|
|
|
|
|
|
BEGIN { |
26
|
68
|
|
|
68
|
|
1275
|
$VERSION = '1.018'; |
27
|
|
|
|
|
|
|
} |
28
|
|
|
|
|
|
|
|
29
|
68
|
|
|
68
|
|
343
|
use Scalar::Util qw(blessed refaddr); |
|
68
|
|
|
|
|
151
|
|
|
68
|
|
|
|
|
2924
|
|
30
|
68
|
|
|
68
|
|
389
|
use Log::Log4perl; |
|
68
|
|
|
|
|
143
|
|
|
68
|
|
|
|
|
481
|
|
31
|
|
|
|
|
|
|
|
32
|
68
|
|
|
68
|
|
3839
|
use RDF::Trine::Error qw(:try); |
|
68
|
|
|
|
|
154
|
|
|
68
|
|
|
|
|
368
|
|
33
|
68
|
|
|
68
|
|
8194
|
use RDF::Trine qw(variable); |
|
68
|
|
|
|
|
162
|
|
|
68
|
|
|
|
|
2614
|
|
34
|
68
|
|
|
68
|
|
391
|
use RDF::Trine::Node; |
|
68
|
|
|
|
|
151
|
|
|
68
|
|
|
|
|
1903
|
|
35
|
68
|
|
|
68
|
|
24347
|
use RDF::Trine::Pattern; |
|
68
|
|
|
|
|
178
|
|
|
68
|
|
|
|
|
1829
|
|
36
|
68
|
|
|
68
|
|
464
|
use RDF::Trine::Store; |
|
68
|
|
|
|
|
157
|
|
|
68
|
|
|
|
|
1152
|
|
37
|
68
|
|
|
68
|
|
24559
|
use RDF::Trine::Model::Dataset; |
|
68
|
|
|
|
|
203
|
|
|
68
|
|
|
|
|
290125
|
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=item C<< new ( $store ) >> |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
Returns a new model over the supplied L<rdf store|RDF::Trine::Store> or a new temporary model. |
42
|
|
|
|
|
|
|
If you provide an unblessed value, it will be used to create a new rdf store. |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=cut |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub new { |
47
|
945
|
|
|
945
|
1
|
3569
|
my $class = shift; |
48
|
945
|
100
|
|
|
|
2620
|
if (@_) { |
49
|
940
|
|
|
|
|
1676
|
my $store = shift; |
50
|
940
|
100
|
|
|
|
4245
|
$store = RDF::Trine::Store->new( $store ) unless (blessed($store)); |
51
|
940
|
|
|
|
|
2624
|
my %args = @_; |
52
|
940
|
|
|
|
|
5248
|
my $self = bless({ |
53
|
|
|
|
|
|
|
store => $store, |
54
|
|
|
|
|
|
|
temporary => 0, |
55
|
|
|
|
|
|
|
added => 0, |
56
|
|
|
|
|
|
|
threshold => -1, |
57
|
|
|
|
|
|
|
%args |
58
|
|
|
|
|
|
|
}, $class); |
59
|
|
|
|
|
|
|
} else { |
60
|
5
|
|
|
|
|
26
|
return $class->temporary_model; |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
=item C<< temporary_model >> |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
Returns a new temporary (non-persistent) model. |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
=cut |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
sub temporary_model { |
71
|
587
|
|
|
587
|
1
|
13166
|
my $class = shift; |
72
|
587
|
|
|
|
|
3215
|
my $store = RDF::Trine::Store::Memory->new(); |
73
|
|
|
|
|
|
|
# my $store = RDF::Trine::Store::DBI->temporary_store(); |
74
|
587
|
|
|
|
|
2029
|
my $self = $class->new( $store ); |
75
|
587
|
|
|
|
|
1368
|
$self->{temporary} = 1; |
76
|
587
|
|
|
|
|
1105
|
$self->{threshold} = 25_000; |
77
|
587
|
|
|
|
|
1407
|
return $self; |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=item C<< dataset_model ( default => \@dgraphs, named => \@ngraphs ) >> |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
Returns a new model object with the default graph mapped to the union of the |
83
|
|
|
|
|
|
|
graphs named in C<< @dgraphs >>, and with available named graphs named in |
84
|
|
|
|
|
|
|
C<< @ngraphs >>. |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
=cut |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub dataset_model { |
89
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
90
|
0
|
|
|
|
|
0
|
my $ds = RDF::Trine::Model::Dataset->new( $self ); |
91
|
0
|
|
|
|
|
0
|
$ds->push_dataset( @_ ); |
92
|
0
|
|
|
|
|
0
|
return $ds; |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=item C<< begin_bulk_ops >> |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
Provides a hint to the backend that many update operations are about to occur. |
98
|
|
|
|
|
|
|
The backend may use this hint to, for example, aggregate many operations into a |
99
|
|
|
|
|
|
|
single operation, or delay index maintenence. After the update operations have |
100
|
|
|
|
|
|
|
been executed, C<< end_bulk_ops >> should be called to ensure the updates are |
101
|
|
|
|
|
|
|
committed to the backend. |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=cut |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
sub begin_bulk_ops { |
106
|
773
|
|
|
773
|
1
|
1473
|
my $self = shift; |
107
|
773
|
|
|
|
|
2188
|
my $store = $self->_store; |
108
|
773
|
50
|
33
|
|
|
6957
|
if (blessed($store) and $store->can('_begin_bulk_ops')) { |
109
|
773
|
|
|
|
|
2630
|
$store->_begin_bulk_ops(); |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
=item C<< end_bulk_ops >> |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
Provides a hint to the backend that a set of bulk operations have been completed |
116
|
|
|
|
|
|
|
and may be committed to the backend. |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=cut |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
sub end_bulk_ops { |
121
|
7228
|
|
|
7228
|
1
|
11123
|
my $self = shift; |
122
|
7228
|
|
|
|
|
15947
|
my $store = $self->_store; |
123
|
7228
|
100
|
66
|
|
|
49696
|
if (blessed($store) and $store->can('_end_bulk_ops')) { |
124
|
7224
|
|
|
|
|
20518
|
$store->_end_bulk_ops(); |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=item C<< logger ( [ $logger ] ) >> |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
Returns the logging object responsible for recording data inserts and deletes. |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
If C<< $logger >> is passed as an argument, sets the logger to this object. |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=cut |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
sub logger { |
137
|
4106
|
|
|
4106
|
1
|
7013
|
my $self = shift; |
138
|
4106
|
100
|
|
|
|
10210
|
if (scalar(@_)) { |
139
|
1
|
|
|
|
|
3
|
$self->{'logger'} = shift; |
140
|
|
|
|
|
|
|
} |
141
|
4106
|
|
|
|
|
11719
|
return $self->{'logger'}; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=item C<< add_statement ( $statement [, $context] ) >> |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
Adds the specified C<< $statement >> to the rdf store. |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=cut |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
sub add_statement { |
151
|
4085
|
|
|
4085
|
1
|
49307
|
my ($self, @args) = @_; |
152
|
4085
|
100
|
|
|
|
16092
|
if ($args[0]->isa('RDF::Trine::Statement')) { |
153
|
4073
|
|
|
|
|
12576
|
foreach my $n ($args[0]->nodes) { |
154
|
12264
|
50
|
66
|
|
|
80414
|
unless (blessed($n) and ($n->isa('RDF::Trine::Node::Resource') or $n->isa('RDF::Trine::Node::Literal') or $n->isa('RDF::Trine::Node::Blank') or $n->isa('RDF::Trine::Node::Nil'))) { |
|
|
|
66
|
|
|
|
|
155
|
0
|
|
|
|
|
0
|
throw RDF::Trine::Error::MethodInvocationError -text => 'Cannot add a pattern (non-ground statement) to a model'; |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
} else { |
159
|
12
|
|
|
|
|
58
|
throw RDF::Trine::Error::MethodInvocationError -text => 'Argument is not an RDF::Trine::Statement'; |
160
|
|
|
|
|
|
|
} |
161
|
4073
|
100
|
|
|
|
12068
|
if ($self->{temporary}) { |
162
|
3338
|
100
|
|
|
|
9792
|
if ($self->{added}++ >= $self->{threshold}) { |
163
|
|
|
|
|
|
|
# warn "*** should upgrade to a DBI store here"; |
164
|
1
|
|
|
|
|
9
|
my $store = RDF::Trine::Store::DBI->temporary_store; |
165
|
1
|
|
|
|
|
7
|
my $iter = $self->get_statements(undef, undef, undef, undef); |
166
|
1
|
50
|
|
|
|
13
|
if ($store->can('_begin_bulk_ops')) { |
167
|
1
|
|
|
|
|
4
|
$store->_begin_bulk_ops(); |
168
|
|
|
|
|
|
|
} |
169
|
1
|
|
|
|
|
8
|
while (my $st = $iter->next) { |
170
|
10
|
|
|
|
|
36
|
$store->add_statement( $st ); |
171
|
|
|
|
|
|
|
} |
172
|
1
|
50
|
|
|
|
7
|
if ($store->can('_begin_bulk_ops')) { |
173
|
1
|
|
|
|
|
10
|
$store->_end_bulk_ops(); |
174
|
|
|
|
|
|
|
} |
175
|
1
|
|
|
|
|
4
|
$self->{store} = $store; |
176
|
1
|
|
|
|
|
32
|
$self->{temporary} = 0; |
177
|
|
|
|
|
|
|
# warn "*** upgraded to a DBI store"; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
4073
|
100
|
|
|
|
10801
|
if (my $log = $self->logger) { |
182
|
3
|
|
|
|
|
7
|
my ($st, $context) = @args; |
183
|
3
|
50
|
|
|
|
8
|
if (defined($context)) { |
184
|
0
|
|
|
|
|
0
|
$st = RDF::Trine::Statement::Quad->new(($st->nodes)[0..2], $context); |
185
|
|
|
|
|
|
|
} |
186
|
3
|
|
|
|
|
10
|
$log->add($st); |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
4073
|
|
|
|
|
10786
|
return $self->_store->add_statement( @args ); |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=item C<< add_hashref ( $hashref [, $context] ) >> |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
Add triples represented in an RDF/JSON-like manner to the model. |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
See C<< as_hashref >> for full documentation of the hashref format. |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
=cut |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
sub add_hashref { |
201
|
49
|
|
|
49
|
1
|
381
|
my $self = shift; |
202
|
49
|
|
|
|
|
93
|
my $index = shift; |
203
|
49
|
|
|
|
|
80
|
my $context = shift; |
204
|
|
|
|
|
|
|
|
205
|
49
|
|
|
|
|
160
|
$self->begin_bulk_ops(); |
206
|
49
|
|
|
|
|
178
|
foreach my $s (keys %$index) { |
207
|
78
|
100
|
|
|
|
554
|
my $ts = ( $s =~ /^_:(.*)$/ ) ? |
208
|
|
|
|
|
|
|
RDF::Trine::Node::Blank->new($1) : |
209
|
|
|
|
|
|
|
RDF::Trine::Node::Resource->new($s); |
210
|
|
|
|
|
|
|
|
211
|
78
|
|
|
|
|
149
|
foreach my $p (keys %{ $index->{$s} }) { |
|
78
|
|
|
|
|
272
|
|
212
|
107
|
|
|
|
|
406
|
my $tp = RDF::Trine::Node::Resource->new($p); |
213
|
|
|
|
|
|
|
|
214
|
107
|
|
|
|
|
205
|
foreach my $O (@{ $index->{$s}->{$p} }) { |
|
107
|
|
|
|
|
286
|
|
215
|
128
|
|
|
|
|
203
|
my $to; |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
# $O should be a hashref, but we can do a little error-correcting. |
218
|
128
|
100
|
|
|
|
377
|
unless (ref $O) { |
219
|
34
|
50
|
|
|
|
192
|
if ($O =~ /^_:/) { |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
220
|
0
|
|
|
|
|
0
|
$O = { 'value'=>$O, 'type'=>'bnode' }; |
221
|
|
|
|
|
|
|
} elsif ($O =~ /^[a-z0-9._\+-]{1,12}:\S+$/i) { |
222
|
0
|
|
|
|
|
0
|
$O = { 'value'=>$O, 'type'=>'uri' }; |
223
|
|
|
|
|
|
|
} elsif ($O =~ /^(.*)\@([a-z]{2})$/) { |
224
|
7
|
|
|
|
|
42
|
$O = { 'value'=>$1, 'type'=>'literal', 'lang'=>$2 }; |
225
|
|
|
|
|
|
|
} else { |
226
|
27
|
|
|
|
|
89
|
$O = { 'value'=>$O, 'type'=>'literal' }; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
128
|
100
|
|
|
|
433
|
if (lc $O->{'type'} eq 'literal') { |
231
|
|
|
|
|
|
|
$to = RDF::Trine::Node::Literal->new( |
232
|
74
|
|
|
|
|
407
|
$O->{'value'}, $O->{'lang'}, $O->{'datatype'}); |
233
|
|
|
|
|
|
|
} else { |
234
|
|
|
|
|
|
|
$to = ( $O->{'value'} =~ /^_:(.*)$/ ) ? |
235
|
|
|
|
|
|
|
RDF::Trine::Node::Blank->new($1) : |
236
|
54
|
100
|
|
|
|
308
|
RDF::Trine::Node::Resource->new($O->{'value'}); |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
128
|
50
|
33
|
|
|
742
|
if ($ts and $tp and $to) { |
|
|
|
33
|
|
|
|
|
240
|
128
|
|
|
|
|
472
|
my $st = RDF::Trine::Statement->new($ts, $tp, $to); |
241
|
128
|
|
|
|
|
377
|
$self->add_statement($st, $context); |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
} |
246
|
49
|
|
|
|
|
142
|
$self->end_bulk_ops(); |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
=item C<< add_iterator ( $iter ) >> |
250
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
Add triples from the statement iterator to the model. |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=cut |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub add_iterator { |
256
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
257
|
0
|
|
|
|
|
0
|
my $iter = shift; |
258
|
0
|
0
|
0
|
|
|
0
|
unless (blessed($iter) and ($iter->is_graph)) { |
259
|
0
|
|
|
|
|
0
|
throw RDF::Trine::Error::MethodInvocationError -text => 'Cannot add a '. ref($iter) . ' iterator to a model, only graphs.'; |
260
|
|
|
|
|
|
|
} |
261
|
0
|
|
|
|
|
0
|
$self->begin_bulk_ops(); |
262
|
0
|
|
|
|
|
0
|
while (my $st = $iter->next) { |
263
|
0
|
|
|
|
|
0
|
$self->add_statement( $st ); |
264
|
|
|
|
|
|
|
} |
265
|
0
|
|
|
|
|
0
|
$self->end_bulk_ops(); |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
=item C<< add_list ( @elements ) >> |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
Adds an rdf:List to the model with the given elements. Returns the node object |
271
|
|
|
|
|
|
|
that is the head of the list. |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
=cut |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
sub add_list { |
276
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
277
|
0
|
|
|
|
|
0
|
my @elements = @_; |
278
|
0
|
|
|
|
|
0
|
my $rdf = RDF::Trine::Namespace->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#'); |
279
|
0
|
0
|
|
|
|
0
|
if (scalar(@elements) == 0) { |
280
|
0
|
|
|
|
|
0
|
return $rdf->nil; |
281
|
|
|
|
|
|
|
} else { |
282
|
0
|
|
|
|
|
0
|
my $head = RDF::Query::Node::Blank->new(); |
283
|
0
|
|
|
|
|
0
|
my $node = shift(@elements); |
284
|
0
|
|
|
|
|
0
|
my $rest = $self->add_list( @elements ); |
285
|
0
|
|
|
|
|
0
|
$self->add_statement( RDF::Trine::Statement->new($head, $rdf->first, $node) ); |
286
|
0
|
|
|
|
|
0
|
$self->add_statement( RDF::Trine::Statement->new($head, $rdf->rest, $rest) ); |
287
|
0
|
|
|
|
|
0
|
return $head; |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
} |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
=item C<< get_list ( $head ) >> |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
Returns a list of nodes that are elements of the rdf:List represented by the |
294
|
|
|
|
|
|
|
supplied head node. |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=cut |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
sub get_list { |
299
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
300
|
1
|
|
|
|
|
3
|
my $head = shift; |
301
|
1
|
|
|
|
|
10
|
my $rdf = RDF::Trine::Namespace->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#'); |
302
|
1
|
|
|
|
|
11
|
my @elements; |
303
|
|
|
|
|
|
|
my %seen; |
304
|
1
|
|
66
|
|
|
13
|
while (blessed($head) and not($head->isa('RDF::Trine::Node::Resource') and $head->uri_value eq $rdf->nil->uri_value)) { |
|
|
|
66
|
|
|
|
|
305
|
291
|
50
|
|
|
|
1400
|
if ($seen{ $head->as_string }++) { |
306
|
0
|
|
|
|
|
0
|
throw RDF::Trine::Error -text => "Loop found during rdf:List traversal"; |
307
|
|
|
|
|
|
|
} |
308
|
291
|
|
|
|
|
2204
|
my @n = $self->objects( $head, $rdf->first ); |
309
|
291
|
50
|
|
|
|
957
|
if (scalar(@n) != 1) { |
310
|
0
|
|
|
|
|
0
|
throw RDF::Trine::Error -text => "Invalid structure found during rdf:List traversal"; |
311
|
|
|
|
|
|
|
} |
312
|
291
|
|
|
|
|
727
|
push(@elements, @n); |
313
|
291
|
|
|
|
|
2137
|
($head) = $self->objects( $head, $rdf->rest ); |
314
|
|
|
|
|
|
|
} |
315
|
1
|
|
|
|
|
3
|
return @elements; |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
=item C<< remove_list ( $head [, orphan_check => 1] ) >> |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
Removes the nodes of type rdf:List that make up the list. Optionally checks each node |
321
|
|
|
|
|
|
|
before removal to make sure that it is not used in any other statements. Returns false |
322
|
|
|
|
|
|
|
if the list was removed completely; returns the first remaining node if the removal |
323
|
|
|
|
|
|
|
was abandoned because of an orphan check. |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
=cut |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
sub remove_list { |
328
|
5
|
|
|
5
|
1
|
69
|
my $self = shift; |
329
|
5
|
|
|
|
|
14
|
my $head = shift; |
330
|
5
|
|
|
|
|
38
|
my $rdf = RDF::Trine::Namespace->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#'); |
331
|
5
|
|
|
|
|
54
|
my %args = @_; |
332
|
5
|
|
|
|
|
13
|
my %seen; |
333
|
|
|
|
|
|
|
|
334
|
5
|
|
66
|
|
|
68
|
while (blessed($head) and not($head->isa('RDF::Trine::Node::Resource') and $head->uri_value eq $rdf->nil->uri_value)) { |
|
|
|
66
|
|
|
|
|
335
|
11
|
50
|
|
|
|
53
|
if ($seen{ $head->as_string }++) { |
336
|
0
|
|
|
|
|
0
|
throw RDF::Trine::Error -text => "Loop found during rdf:List traversal"; |
337
|
|
|
|
|
|
|
} |
338
|
11
|
|
|
|
|
57
|
my $stream = $self->get_statements($head, undef, undef); |
339
|
11
|
|
|
|
|
29
|
my %statements; |
340
|
11
|
|
|
|
|
50
|
while (my $st = $stream->next) { |
341
|
|
|
|
|
|
|
my $statement_type = { |
342
|
|
|
|
|
|
|
$rdf->first->uri => 'rdf:first', |
343
|
|
|
|
|
|
|
$rdf->rest->uri => 'rdf:rest', |
344
|
|
|
|
|
|
|
$rdf->type->uri => 'rdf:type', |
345
|
29
|
|
100
|
|
|
226
|
}->{$st->predicate->uri} || 'other'; |
346
|
29
|
50
|
66
|
|
|
131
|
$statement_type = 'other' |
347
|
|
|
|
|
|
|
if $statement_type eq 'rdf:type' && !$st->object->equal($rdf->List); |
348
|
29
|
|
|
|
|
63
|
push @{$statements{$statement_type}}, $st; |
|
29
|
|
|
|
|
156
|
|
349
|
|
|
|
|
|
|
} |
350
|
11
|
100
|
|
|
|
51
|
if ($args{orphan_check}) { |
351
|
3
|
100
|
66
|
|
|
16
|
return $head if defined $statements{other} && scalar(@{ $statements{other} }) > 0; |
|
1
|
|
|
|
|
33
|
|
352
|
2
|
100
|
|
|
|
13
|
return $head if $self->count_statements(undef, undef, $head) > 0; |
353
|
|
|
|
|
|
|
} |
354
|
9
|
100
|
33
|
|
|
78
|
unless (defined $statements{'rdf:first'} and defined $statements{'rdf:rest'} and scalar(@{$statements{'rdf:first'} })==1 and scalar(@{ $statements{'rdf:rest'} })==1) { |
|
9
|
|
66
|
|
|
63
|
|
|
8
|
|
66
|
|
|
38
|
|
355
|
1
|
|
|
|
|
25
|
throw RDF::Trine::Error -text => "Invalid structure found during rdf:List traversal"; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
$self->remove_statement($_) |
358
|
8
|
|
|
|
|
17
|
foreach (@{$statements{'rdf:first'}}, @{$statements{'rdf:rest'}}, @{$statements{'rdf:type'}}); |
|
8
|
|
|
|
|
24
|
|
|
8
|
|
|
|
|
18
|
|
|
8
|
|
|
|
|
53
|
|
359
|
|
|
|
|
|
|
|
360
|
8
|
|
|
|
|
51
|
$head = $statements{'rdf:rest'}->[0]->object; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
2
|
|
|
|
|
8
|
return; |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
=item C<< get_sequence ( $seq ) >> |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
Returns a list of nodes that are elements of the rdf:Seq sequence. |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
=cut |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
sub get_sequence { |
373
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
374
|
0
|
|
|
|
|
0
|
my $head = shift; |
375
|
0
|
|
|
|
|
0
|
my $rdf = RDF::Trine::Namespace->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#'); |
376
|
0
|
|
|
|
|
0
|
my @elements; |
377
|
0
|
|
|
|
|
0
|
my $i = 1; |
378
|
0
|
|
|
|
|
0
|
while (1) { |
379
|
0
|
|
|
|
|
0
|
my $method = '_' . $i; |
380
|
0
|
|
|
|
|
0
|
my (@elem) = $self->objects( $head, $rdf->$method() ); |
381
|
0
|
0
|
|
|
|
0
|
unless (scalar(@elem)) { |
382
|
0
|
|
|
|
|
0
|
last; |
383
|
|
|
|
|
|
|
} |
384
|
0
|
0
|
|
|
|
0
|
if (scalar(@elem) > 1) { |
385
|
0
|
|
|
|
|
0
|
my $count = scalar(@elem); |
386
|
0
|
|
|
|
|
0
|
throw RDF::Trine::Error -text => "Invalid structure found during rdf:Seq access: $count elements found for element $i"; |
387
|
|
|
|
|
|
|
} |
388
|
0
|
|
|
|
|
0
|
my $elem = $elem[0]; |
389
|
0
|
0
|
|
|
|
0
|
last unless (blessed($elem)); |
390
|
0
|
|
|
|
|
0
|
push(@elements, $elem); |
391
|
0
|
|
|
|
|
0
|
$i++; |
392
|
|
|
|
|
|
|
} |
393
|
0
|
|
|
|
|
0
|
return @elements; |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
=item C<< remove_statement ( $statement [, $context]) >> |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
Removes the specified C<< $statement >> from the rdf store. |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
=cut |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
sub remove_statement { |
403
|
26
|
|
|
26
|
1
|
61
|
my $self = shift; |
404
|
26
|
|
|
|
|
89
|
my @args = @_; |
405
|
26
|
100
|
|
|
|
109
|
if (my $log = $self->logger) { |
406
|
1
|
|
|
|
|
3
|
my ($st, $context) = @args; |
407
|
1
|
50
|
|
|
|
3
|
if (defined($context)) { |
408
|
0
|
|
|
|
|
0
|
$st = RDF::Trine::Statement::Quad->new(($st->nodes)[0..2], $context); |
409
|
|
|
|
|
|
|
} |
410
|
1
|
|
|
|
|
5
|
$log->delete($st); |
411
|
|
|
|
|
|
|
} |
412
|
26
|
|
|
|
|
102
|
return $self->_store->remove_statement( @args ); |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
=item C<< remove_statements ( $subject, $predicate, $object [, $context] ) >> |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
Removes all statements matching the supplied C<< $statement >> pattern from the rdf store. |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
=cut |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
sub remove_statements { |
422
|
6
|
|
|
6
|
1
|
63
|
my $self = shift; |
423
|
6
|
50
|
|
|
|
30
|
if (my $log = $self->logger) { |
424
|
0
|
|
|
|
|
0
|
$log->delete($_) foreach (@_); |
425
|
|
|
|
|
|
|
} |
426
|
6
|
|
|
|
|
28
|
return $self->_store->remove_statements( @_ ); |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
=item C<< size >> |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
Returns the number of statements in the model. |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
=cut |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
sub size { |
436
|
26
|
|
|
26
|
1
|
475
|
my $self = shift; |
437
|
26
|
|
|
|
|
93
|
$self->end_bulk_ops(); |
438
|
26
|
|
|
|
|
106
|
return $self->count_statements(undef, undef, undef, undef); |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
=item C<< etag >> |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
If the model is based on a store that has the capability and knowledge to |
444
|
|
|
|
|
|
|
support caching, this method returns a persistent token that will remain |
445
|
|
|
|
|
|
|
consistent as long as the store's data doesn't change. This token is acceptable |
446
|
|
|
|
|
|
|
for use as an HTTP ETag. |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
=cut |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
sub etag { |
451
|
3
|
|
|
3
|
1
|
9
|
my $self = shift; |
452
|
3
|
|
|
|
|
8
|
my $store = $self->_store; |
453
|
3
|
50
|
|
|
|
9
|
if ($store) { |
454
|
3
|
|
|
|
|
10
|
return $store->etag; |
455
|
|
|
|
|
|
|
} |
456
|
0
|
|
|
|
|
0
|
return; |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
=item C<< supports ( [ $feature ] ) >> |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
If C<< $feature >> is specified, returns true if the feature is supported by the |
462
|
|
|
|
|
|
|
underlying store, false otherwise. If C<< $feature >> is not specified, returns |
463
|
|
|
|
|
|
|
a list of supported features. |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
=cut |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
sub supports { |
468
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
469
|
0
|
|
|
|
|
0
|
my $store = $self->_store; |
470
|
0
|
0
|
|
|
|
0
|
if ($store) { |
471
|
0
|
|
|
|
|
0
|
return $store->supports( @_ ); |
472
|
|
|
|
|
|
|
} |
473
|
0
|
|
|
|
|
0
|
return; |
474
|
|
|
|
|
|
|
} |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=item C<< count_statements ( $subject, $predicate, $object ) >> |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
Returns a count of all the statements matching the specified subject, |
479
|
|
|
|
|
|
|
predicate and objects. Any of the arguments may be undef to match any value. |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
=cut |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
sub count_statements { |
484
|
710
|
|
|
710
|
1
|
29636
|
my $self = shift; |
485
|
710
|
|
|
|
|
2271
|
$self->end_bulk_ops(); |
486
|
|
|
|
|
|
|
|
487
|
710
|
100
|
|
|
|
1995
|
if (scalar(@_) >= 4) { |
488
|
58
|
|
|
|
|
105
|
my $graph = $_[3]; |
489
|
58
|
100
|
100
|
|
|
316
|
if (blessed($graph) and $graph->isa('RDF::Trine::Node::Resource') and $graph->uri_value eq 'tag:gwilliams@cpan.org,2010-01-01:RT:ALL') { |
|
|
|
100
|
|
|
|
|
490
|
1
|
|
|
|
|
4
|
$_[3] = undef; |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
} |
493
|
710
|
|
|
|
|
1442
|
return $self->_store->count_statements( @_ ); |
494
|
|
|
|
|
|
|
} |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
=item C<< get_statements ($subject, $predicate, $object [, $context] ) >> |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
Returns an L<iterator|RDF::Trine::Iterator> of all statements matching the specified |
499
|
|
|
|
|
|
|
subject, predicate and objects from the rdf store. Any of the arguments may be undef |
500
|
|
|
|
|
|
|
to match any value. |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
If three or fewer arguments are given, the statements returned will be matched |
503
|
|
|
|
|
|
|
based on triple semantics (the graph union of triples from all the named |
504
|
|
|
|
|
|
|
graphs). If four arguments are given (even if C<< $context >> is undef), |
505
|
|
|
|
|
|
|
statements will be matched based on quad semantics (the union of all quads in |
506
|
|
|
|
|
|
|
the underlying store). |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
=cut |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
sub get_statements { |
511
|
2526
|
|
|
2526
|
1
|
6671
|
my $self = shift; |
512
|
2526
|
|
|
|
|
6446
|
$self->end_bulk_ops(); |
513
|
|
|
|
|
|
|
|
514
|
2526
|
|
|
|
|
7162
|
my @pos = qw(subject predicate object graph); |
515
|
2526
|
|
|
|
|
7360
|
foreach my $i (0 .. $#_) { |
516
|
9467
|
|
|
|
|
15318
|
my $n = $_[$i]; |
517
|
9467
|
100
|
|
|
|
20521
|
next unless defined($n); # undef is OK |
518
|
6585
|
100
|
66
|
|
|
37250
|
next if (blessed($n) and $n->isa('RDF::Trine::Node')); # node objects are OK |
519
|
4
|
|
|
|
|
11
|
my $pos = $pos[$i]; |
520
|
4
|
|
|
|
|
12
|
local($Data::Dumper::Indent) = 0; |
521
|
4
|
|
|
|
|
41
|
my $ser = Data::Dumper->Dump([$n], [$pos]); |
522
|
4
|
|
|
|
|
348
|
throw RDF::Trine::Error::MethodInvocationError -text => "get_statements called with a value that isn't undef or a node object: $ser"; |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
|
525
|
2522
|
100
|
|
|
|
7246
|
if (scalar(@_) >= 4) { |
526
|
2169
|
|
|
|
|
3955
|
my $graph = $_[3]; |
527
|
2169
|
50
|
100
|
|
|
10684
|
if (blessed($graph) and $graph->isa('RDF::Trine::Node::Resource') and $graph->uri_value eq 'tag:gwilliams@cpan.org,2010-01-01:RT:ALL') { |
|
|
|
66
|
|
|
|
|
528
|
0
|
|
|
|
|
0
|
$_[3] = undef; |
529
|
|
|
|
|
|
|
} |
530
|
|
|
|
|
|
|
} |
531
|
2522
|
|
|
|
|
5632
|
return $self->_store->get_statements( @_ ); |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
=item C<< get_pattern ( $bgp [, $context] [, %args ] ) >> |
535
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
Returns a stream object of all bindings matching the specified graph pattern. |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
If C<< $context >> is given, restricts BGP matching to only quads with the |
539
|
|
|
|
|
|
|
C<< $context >> value. |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
C<< %args >> may contain an 'orderby' key-value pair to request a specific |
542
|
|
|
|
|
|
|
ordering based on variable name. The value for the 'orderby' key should be an |
543
|
|
|
|
|
|
|
ARRAY reference containing variable name and direction ('ASC' or 'DESC') tuples. |
544
|
|
|
|
|
|
|
A valid C<< %args >> hash, therefore, might look like |
545
|
|
|
|
|
|
|
C<< orderby => [qw(name ASC)] >> (corresponding to a SPARQL-like request to |
546
|
|
|
|
|
|
|
'ORDER BY ASC(?name)'). |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
=cut |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
sub get_pattern { |
551
|
955
|
|
|
955
|
1
|
11541
|
my $self = shift; |
552
|
955
|
|
|
|
|
1520
|
my $bgp = shift; |
553
|
955
|
|
|
|
|
1490
|
my $context = shift; |
554
|
955
|
|
|
|
|
2148
|
my @args = @_; |
555
|
955
|
|
|
|
|
2524
|
my %args = @args; |
556
|
|
|
|
|
|
|
|
557
|
955
|
|
|
|
|
2682
|
$self->end_bulk_ops(); |
558
|
955
|
100
|
66
|
|
|
10038
|
my (@triples) = ($bgp->isa('RDF::Trine::Statement') or $bgp->isa('RDF::Query::Algebra::Filter')) |
559
|
|
|
|
|
|
|
? $bgp |
560
|
|
|
|
|
|
|
: $bgp->triples; |
561
|
955
|
100
|
|
|
|
2631
|
unless (@triples) { |
562
|
5
|
|
|
|
|
70
|
throw RDF::Trine::Error::CompilationError -text => 'Cannot call get_pattern() with empty pattern'; |
563
|
|
|
|
|
|
|
} |
564
|
|
|
|
|
|
|
|
565
|
950
|
|
|
|
|
2021
|
my $store = $self->_store; |
566
|
|
|
|
|
|
|
# while almost all models will delegate get_pattern() to the underlying |
567
|
|
|
|
|
|
|
# store object, in some cases this isn't possible (union models don't have |
568
|
|
|
|
|
|
|
# a single store, so have to fall back to the model-specific get_pattern() |
569
|
|
|
|
|
|
|
# implementation). |
570
|
950
|
100
|
100
|
|
|
6051
|
if (blessed($store) and $store->can('get_pattern')) { |
571
|
41
|
|
|
|
|
153
|
return $self->_store->get_pattern( $bgp, $context, @args ); |
572
|
|
|
|
|
|
|
} else { |
573
|
909
|
100
|
|
|
|
2973
|
if ($bgp->isa('RDF::Trine::Pattern')) { |
574
|
903
|
|
|
|
|
2904
|
$bgp = $bgp->sort_for_join_variables(); |
575
|
|
|
|
|
|
|
} |
576
|
909
|
|
|
|
|
2622
|
my $iter = $self->_get_pattern( $bgp, $context ); |
577
|
909
|
100
|
|
|
|
2741
|
if (my $ob = $args{orderby}) { |
578
|
900
|
|
|
|
|
2458
|
my @order = @$ob; |
579
|
900
|
100
|
|
|
|
2624
|
if (scalar(@order) % 2) { |
580
|
1
|
|
|
|
|
10
|
throw RDF::Trine::Error::MethodInvocationError -text => "Invalid arguments to orderby argument in get_pattern"; |
581
|
|
|
|
|
|
|
} |
582
|
|
|
|
|
|
|
|
583
|
899
|
|
|
|
|
2868
|
my @results = $iter->get_all(); |
584
|
899
|
|
|
|
|
2239
|
my $order_vars = scalar(@order) / 2; |
585
|
899
|
|
|
|
|
1518
|
my %seen; |
586
|
899
|
|
|
|
|
1959
|
foreach my $r (@results) { |
587
|
1687
|
|
|
|
|
3887
|
foreach my $var (keys %$r) { |
588
|
6382
|
|
|
|
|
10747
|
$seen{$var}++; |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
} |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
@results = sort { |
593
|
899
|
|
|
|
|
2303
|
my $r = 0; |
|
1450
|
|
|
|
|
2123
|
|
594
|
1450
|
|
|
|
|
2895
|
foreach my $i (0 .. ($order_vars-1)) { |
595
|
2361
|
|
|
|
|
3894
|
my $var = $order[$i*2]; |
596
|
2361
|
|
|
|
|
3964
|
my $rev = ($order[$i*2+1] =~ /DESC/i); |
597
|
2361
|
|
|
|
|
5995
|
$r = RDF::Trine::Node::compare( $a->{$var}, $b->{$var} ); |
598
|
2361
|
100
|
|
|
|
5005
|
$r *= -1 if ($rev); |
599
|
2361
|
100
|
|
|
|
5088
|
last if ($r); |
600
|
|
|
|
|
|
|
} |
601
|
|
|
|
|
|
|
$r; |
602
|
|
|
|
|
|
|
} @results; |
603
|
|
|
|
|
|
|
|
604
|
899
|
|
|
|
|
1475
|
my @sortedby; |
605
|
899
|
|
|
|
|
2312
|
foreach my $i (0 .. ($order_vars-1)) { |
606
|
2631
|
|
|
|
|
4634
|
my $var = $order[$i*2]; |
607
|
2631
|
|
|
|
|
4015
|
my $dir = $order[$i*2+1]; |
608
|
2631
|
100
|
|
|
|
7718
|
push(@sortedby, $var, $dir) if ($seen{$var}); |
609
|
|
|
|
|
|
|
} |
610
|
899
|
|
|
|
|
3685
|
$iter = RDF::Trine::Iterator::Bindings->new(\@results, undef, sorted_by => \@sortedby); |
611
|
|
|
|
|
|
|
} |
612
|
908
|
|
|
|
|
11684
|
return $iter; |
613
|
|
|
|
|
|
|
} |
614
|
|
|
|
|
|
|
} |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
=item C<< get_sparql ( $sparql ) >> |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
Returns a stream object of all bindings matching the specified graph pattern. |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
=cut |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
sub get_sparql { |
623
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
624
|
0
|
|
|
|
|
0
|
return $self->_store->get_sparql( @_ ); |
625
|
|
|
|
|
|
|
} |
626
|
|
|
|
|
|
|
|
627
|
|
|
|
|
|
|
sub _get_pattern { |
628
|
927
|
|
|
927
|
|
1481
|
my $self = shift; |
629
|
927
|
|
|
|
|
1390
|
my $bgp = shift; |
630
|
927
|
|
|
|
|
1438
|
my $context = shift; |
631
|
927
|
|
|
|
|
1738
|
my @args = @_; |
632
|
|
|
|
|
|
|
|
633
|
927
|
100
|
66
|
|
|
7283
|
my (@triples) = ($bgp->isa('RDF::Trine::Statement') or $bgp->isa('RDF::Query::Algebra::Filter')) |
634
|
|
|
|
|
|
|
? $bgp |
635
|
|
|
|
|
|
|
: $bgp->triples; |
636
|
927
|
100
|
|
|
|
2290
|
if (1 == scalar(@triples)) { |
637
|
918
|
|
|
|
|
1683
|
my $t = shift(@triples); |
638
|
918
|
|
|
|
|
2625
|
my @nodes = $t->nodes; |
639
|
918
|
|
|
|
|
1632
|
my %vars; |
640
|
918
|
|
|
|
|
2114
|
my @names = qw(subject predicate object context); |
641
|
918
|
|
|
|
|
2374
|
foreach my $n (0 .. $#nodes) { |
642
|
3542
|
100
|
|
|
|
10481
|
if ($nodes[$n]->isa('RDF::Trine::Node::Variable')) { |
643
|
3438
|
|
|
|
|
7808
|
$vars{ $names[ $n ] } = $nodes[$n]->name; |
644
|
|
|
|
|
|
|
} |
645
|
|
|
|
|
|
|
} |
646
|
918
|
50
|
|
|
|
2442
|
if ($context) { |
647
|
0
|
|
|
|
|
0
|
$nodes[3] = $context; |
648
|
|
|
|
|
|
|
} |
649
|
918
|
|
|
|
|
2735
|
my $iter = $self->get_statements( @nodes ); |
650
|
918
|
|
|
|
|
3127
|
my @vars = values %vars; |
651
|
|
|
|
|
|
|
my $sub = sub { |
652
|
2641
|
|
|
2641
|
|
6947
|
my $row = $iter->next; |
653
|
2641
|
100
|
|
|
|
6524
|
return unless ($row); |
654
|
1723
|
|
|
|
|
4414
|
my %data = map { $vars{ $_ } => $row->$_() } (keys %vars); |
|
6426
|
|
|
|
|
18317
|
|
655
|
1723
|
|
|
|
|
8091
|
return RDF::Trine::VariableBindings->new( \%data ); |
656
|
918
|
|
|
|
|
3416
|
}; |
657
|
918
|
|
|
|
|
5389
|
return RDF::Trine::Iterator::Bindings->new( $sub, \@vars ); |
658
|
|
|
|
|
|
|
} else { |
659
|
9
|
|
|
|
|
19
|
my $t = pop(@triples); |
660
|
9
|
|
|
|
|
25
|
my $rhs = $self->_get_pattern( RDF::Trine::Pattern->new( $t ), $context, @args ); |
661
|
9
|
|
|
|
|
40
|
my $lhs = $self->_get_pattern( RDF::Trine::Pattern->new( @triples ), $context, @args ); |
662
|
9
|
|
|
|
|
23
|
my @inner; |
663
|
9
|
|
|
|
|
36
|
while (my $row = $rhs->next) { |
664
|
21
|
|
|
|
|
77
|
push(@inner, $row); |
665
|
|
|
|
|
|
|
} |
666
|
9
|
|
|
|
|
25
|
my @results; |
667
|
9
|
|
|
|
|
26
|
while (my $row = $lhs->next) { |
668
|
15
|
|
|
|
|
33
|
RESULT: foreach my $irow (@inner) { |
669
|
34
|
|
|
|
|
50
|
my %keysa; |
670
|
34
|
|
|
|
|
75
|
my @keysa = keys %$irow; |
671
|
34
|
|
|
|
|
86
|
@keysa{ @keysa } = (1) x scalar(@keysa); |
672
|
34
|
|
|
|
|
68
|
my @shared = grep { exists $keysa{ $_ } } (keys %$row); |
|
34
|
|
|
|
|
85
|
|
673
|
34
|
|
|
|
|
61
|
foreach my $key (@shared) { |
674
|
25
|
|
|
|
|
43
|
my $val_a = $irow->{ $key }; |
675
|
25
|
|
|
|
|
36
|
my $val_b = $row->{ $key }; |
676
|
25
|
50
|
33
|
|
|
101
|
next unless (defined($val_a) and defined($val_b)); |
677
|
25
|
|
|
|
|
71
|
my $equal = $val_a->equal( $val_b ); |
678
|
25
|
100
|
|
|
|
64
|
unless ($equal) { |
679
|
12
|
|
|
|
|
44
|
next RESULT; |
680
|
|
|
|
|
|
|
} |
681
|
|
|
|
|
|
|
} |
682
|
|
|
|
|
|
|
|
683
|
22
|
|
|
|
|
44
|
my $jrow = { (map { $_ => $irow->{$_} } grep { defined($irow->{$_}) } keys %$irow), (map { $_ => $row->{$_} } grep { defined($row->{$_}) } keys %$row) }; |
|
35
|
|
|
|
|
80
|
|
|
35
|
|
|
|
|
71
|
|
|
22
|
|
|
|
|
67
|
|
|
22
|
|
|
|
|
44
|
|
684
|
22
|
|
|
|
|
69
|
push(@results, RDF::Trine::VariableBindings->new($jrow)); |
685
|
|
|
|
|
|
|
} |
686
|
|
|
|
|
|
|
} |
687
|
9
|
|
|
|
|
40
|
my $result = RDF::Trine::Iterator::Bindings->new( \@results, [ $bgp->referenced_variables ] ); |
688
|
9
|
|
|
|
|
49
|
return $result; |
689
|
|
|
|
|
|
|
} |
690
|
|
|
|
|
|
|
} |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
=item C<< get_graphs >> |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
=item C<< get_contexts >> |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
Returns an L<iterator|RDF::Trine::Iterator> containing the nodes representing |
697
|
|
|
|
|
|
|
the named graphs in the model. |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
=cut |
700
|
|
|
|
|
|
|
|
701
|
|
|
|
|
|
|
sub get_contexts { |
702
|
2
|
|
|
2
|
1
|
14
|
my $self = shift; |
703
|
2
|
|
|
|
|
7
|
my $store = $self->_store; |
704
|
2
|
|
|
|
|
5
|
$self->end_bulk_ops(); |
705
|
2
|
|
|
|
|
8
|
my $iter = $store->get_contexts( @_ ); |
706
|
2
|
50
|
|
|
|
6
|
if (wantarray) { |
707
|
0
|
|
|
|
|
0
|
return $iter->get_all; |
708
|
|
|
|
|
|
|
} else { |
709
|
2
|
|
|
|
|
6
|
return $iter; |
710
|
|
|
|
|
|
|
} |
711
|
|
|
|
|
|
|
} |
712
|
|
|
|
|
|
|
*get_graphs = \&get_contexts; |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
=item C<< as_stream >> |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
Returns an L<iterator|RDF::Trine::Iterator> containing every statement in the model. |
717
|
|
|
|
|
|
|
|
718
|
|
|
|
|
|
|
=cut |
719
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
sub as_stream { |
721
|
788
|
|
|
788
|
1
|
2438
|
my $self = shift; |
722
|
788
|
|
|
|
|
2178
|
$self->end_bulk_ops(); |
723
|
788
|
|
|
|
|
1981
|
my $st = RDF::Trine::Statement::Quad->new( map { variable($_) } qw(s p o g) ); |
|
3152
|
|
|
|
|
7721
|
|
724
|
788
|
|
|
|
|
3747
|
my $pat = RDF::Trine::Pattern->new( $st ); |
725
|
788
|
|
|
|
|
3111
|
my $stream = $self->get_pattern( $pat, undef, orderby => [ qw(s ASC p ASC o ASC) ] ); |
726
|
788
|
|
|
|
|
3354
|
return $stream->as_statements( qw(s p o g) ); |
727
|
|
|
|
|
|
|
} |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
=item C<< as_hashref >> |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
Returns a hashref representing the model in an RDF/JSON-like manner. |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
A graph like this (in Turtle): |
734
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
@prefix ex: <http://example.com/> . |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
ex:subject1 |
738
|
|
|
|
|
|
|
ex:predicate1 |
739
|
|
|
|
|
|
|
"Foo"@en , |
740
|
|
|
|
|
|
|
"Bar"^^ex:datatype1 . |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
_:bnode1 |
743
|
|
|
|
|
|
|
ex:predicate2 |
744
|
|
|
|
|
|
|
ex:object2 ; |
745
|
|
|
|
|
|
|
ex:predicate3 ; |
746
|
|
|
|
|
|
|
_:bnode3 . |
747
|
|
|
|
|
|
|
|
748
|
|
|
|
|
|
|
Is represented like this as a hashref: |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
{ |
751
|
|
|
|
|
|
|
"http://example.com/subject1" => { |
752
|
|
|
|
|
|
|
"http://example.com/predicate1" => [ |
753
|
|
|
|
|
|
|
{ 'type'=>'literal', 'value'=>"Foo", 'lang'=>"en" }, |
754
|
|
|
|
|
|
|
{ 'type'=>'literal', 'value'=>"Bar", 'datatype'=>"http://example.com/datatype1" }, |
755
|
|
|
|
|
|
|
], |
756
|
|
|
|
|
|
|
}, |
757
|
|
|
|
|
|
|
"_:bnode1" => { |
758
|
|
|
|
|
|
|
"http://example.com/predicate2" => [ |
759
|
|
|
|
|
|
|
{ 'type'=>'uri', 'value'=>"http://example.com/object2" }, |
760
|
|
|
|
|
|
|
], |
761
|
|
|
|
|
|
|
"http://example.com/predicate2" => [ |
762
|
|
|
|
|
|
|
{ 'type'=>'bnode', 'value'=>"_:bnode3" }, |
763
|
|
|
|
|
|
|
], |
764
|
|
|
|
|
|
|
}, |
765
|
|
|
|
|
|
|
} |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
Note that the type of subjects (resource or blank node) is indicated |
768
|
|
|
|
|
|
|
entirely by the convention of starting blank nodes with "_:". |
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
This hashref structure is compatible with RDF/JSON and with the ARC2 |
771
|
|
|
|
|
|
|
library for PHP. |
772
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
=cut |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
sub as_hashref { |
776
|
2
|
|
|
2
|
1
|
7
|
my $self = shift; |
777
|
2
|
|
|
|
|
9
|
$self->end_bulk_ops(); |
778
|
2
|
|
|
|
|
10
|
return $self->as_stream->as_hashref; |
779
|
|
|
|
|
|
|
} |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
=item C<< as_graphviz >> |
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
Returns a L<GraphViz> object of the RDF graph of this model, ignoring graph |
784
|
|
|
|
|
|
|
names/contexts. |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
This method will attempt to load the L<GraphViz> module at runtime and will fail |
787
|
|
|
|
|
|
|
if the module is unavailable. |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
=cut |
790
|
|
|
|
|
|
|
|
791
|
|
|
|
|
|
|
sub as_graphviz { |
792
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
793
|
0
|
|
|
|
|
0
|
require GraphViz; |
794
|
0
|
|
|
|
|
0
|
my $g = GraphViz->new(); |
795
|
0
|
|
|
|
|
0
|
my %seen; |
796
|
0
|
|
|
|
|
0
|
my $iter = $self->as_stream; |
797
|
0
|
|
|
|
|
0
|
while (my $t = $iter->next) { |
798
|
0
|
|
|
|
|
0
|
my @nodes; |
799
|
0
|
|
|
|
|
0
|
foreach my $pos (qw(subject object)) { |
800
|
0
|
|
|
|
|
0
|
my $n = $t->$pos(); |
801
|
0
|
0
|
|
|
|
0
|
my $label = ($n->isa('RDF::Trine::Node::Literal')) ? $n->literal_value : $n->as_string; |
802
|
0
|
|
|
|
|
0
|
push(@nodes, $label); |
803
|
0
|
0
|
|
|
|
0
|
unless ($seen{ $label }++) { |
804
|
0
|
|
|
|
|
0
|
$g->add_node( $label ); |
805
|
|
|
|
|
|
|
} |
806
|
|
|
|
|
|
|
} |
807
|
0
|
|
|
|
|
0
|
$g->add_edge( @nodes, label => $t->predicate->as_string ); |
808
|
|
|
|
|
|
|
} |
809
|
0
|
|
|
|
|
0
|
return $g; |
810
|
|
|
|
|
|
|
} |
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
=back |
813
|
|
|
|
|
|
|
|
814
|
|
|
|
|
|
|
=head2 Node-Centric Graph API |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
=over 4 |
817
|
|
|
|
|
|
|
|
818
|
|
|
|
|
|
|
=item C<< subjects ( $predicate, $object ) >> |
819
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
Returns a list of the nodes that appear as the subject of statements with the |
821
|
|
|
|
|
|
|
specified C<< $predicate >> and C<< $object >>. Either of the two arguments may |
822
|
|
|
|
|
|
|
be undef to signify a wildcard. |
823
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
=cut |
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
sub subjects { |
827
|
14
|
|
|
14
|
1
|
35
|
my $self = shift; |
828
|
14
|
|
|
|
|
34
|
my $pred = shift; |
829
|
14
|
|
|
|
|
30
|
my $obj = shift; |
830
|
14
|
|
|
|
|
30
|
my $graph = shift; |
831
|
14
|
|
|
|
|
59
|
$self->end_bulk_ops(); |
832
|
14
|
|
|
|
|
70
|
my $iter = $self->get_statements( undef, $pred, $obj, $graph ); |
833
|
14
|
|
|
|
|
36
|
my %nodes; |
834
|
14
|
|
|
|
|
70
|
while (my $st = $iter->next) { |
835
|
22
|
|
|
|
|
74
|
my $subj = $st->subject; |
836
|
22
|
|
|
|
|
96
|
$nodes{ $subj->as_string } = $subj; |
837
|
|
|
|
|
|
|
} |
838
|
14
|
100
|
|
|
|
50
|
if (wantarray) { |
839
|
10
|
|
|
|
|
250
|
return values(%nodes); |
840
|
|
|
|
|
|
|
} else { |
841
|
4
|
|
|
|
|
26
|
return RDF::Trine::Iterator->new( [values(%nodes)] ); |
842
|
|
|
|
|
|
|
} |
843
|
|
|
|
|
|
|
} |
844
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
=item C<< predicates ( $subject, $object ) >> |
846
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
Returns a list of the nodes that appear as the predicate of statements with the |
848
|
|
|
|
|
|
|
specified C<< $subject >> and C<< $object >>. Either of the two arguments may |
849
|
|
|
|
|
|
|
be undef to signify a wildcard. |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
=cut |
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
sub predicates { |
854
|
12
|
|
|
12
|
1
|
29
|
my $self = shift; |
855
|
12
|
|
|
|
|
24
|
my $subj = shift; |
856
|
12
|
|
|
|
|
23
|
my $obj = shift; |
857
|
12
|
|
|
|
|
27
|
my $graph = shift; |
858
|
12
|
|
|
|
|
50
|
$self->end_bulk_ops(); |
859
|
12
|
|
|
|
|
52
|
my $iter = $self->get_statements( $subj, undef, $obj, $graph ); |
860
|
12
|
|
|
|
|
29
|
my %nodes; |
861
|
12
|
|
|
|
|
50
|
while (my $st = $iter->next) { |
862
|
20
|
|
|
|
|
78
|
my $pred = $st->predicate; |
863
|
20
|
|
|
|
|
83
|
$nodes{ $pred->as_string } = $pred; |
864
|
|
|
|
|
|
|
} |
865
|
12
|
100
|
|
|
|
39
|
if (wantarray) { |
866
|
8
|
|
|
|
|
236
|
return values(%nodes); |
867
|
|
|
|
|
|
|
} else { |
868
|
4
|
|
|
|
|
19
|
return RDF::Trine::Iterator->new( [values(%nodes)] ); |
869
|
|
|
|
|
|
|
} |
870
|
|
|
|
|
|
|
} |
871
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
=item C<< objects ( $subject, $predicate [, $graph ] [, %options ] ) >> |
873
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
Returns a list of the nodes that appear as the object of statements with the |
875
|
|
|
|
|
|
|
specified C<< $subject >> and C<< $predicate >>. Either of the two arguments |
876
|
|
|
|
|
|
|
may be undef to signify a wildcard. You can further filter objects using the |
877
|
|
|
|
|
|
|
C<< %options >> argument. Keys in C<< %options >> indicate the restriction type |
878
|
|
|
|
|
|
|
and may be 'type', 'language', or 'datatype'. The value of the 'type' key may be |
879
|
|
|
|
|
|
|
one of 'node', 'nil', 'blank', 'resource', 'literal', or 'variable'. The use of |
880
|
|
|
|
|
|
|
either 'language' or 'datatype' restrict objects to literal nodes with a |
881
|
|
|
|
|
|
|
specific language or datatype value, respectively. |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
=cut |
884
|
|
|
|
|
|
|
|
885
|
|
|
|
|
|
|
sub objects { |
886
|
1319
|
|
|
1319
|
1
|
5797
|
my $self = shift; |
887
|
1319
|
|
|
|
|
2501
|
my $subj = shift; |
888
|
1319
|
|
|
|
|
2229
|
my $pred = shift; |
889
|
1319
|
50
|
|
|
|
5235
|
my ($graph, %options) = (@_ % 2 == 0) ? (undef, @_) : @_; |
890
|
1319
|
|
|
|
|
2621
|
my $type = $options{type}; |
891
|
1319
|
100
|
100
|
|
|
6782
|
$type = 'literal' if ($options{language} or $options{datatype}); |
892
|
1319
|
100
|
100
|
|
|
3944
|
if ($options{datatype} and not blessed($options{datatype})) { |
893
|
1
|
|
|
|
|
6
|
$options{datatype} = RDF::Trine::Node::Resource->new($options{datatype}); |
894
|
|
|
|
|
|
|
} |
895
|
|
|
|
|
|
|
|
896
|
1319
|
100
|
|
|
|
3129
|
if (defined $type) { |
897
|
6
|
50
|
|
|
|
30
|
if ($type =~ /^(node|nil|blank|resource|literal|variable)$/) { |
898
|
6
|
|
|
|
|
18
|
$type = "is_$type"; |
899
|
|
|
|
|
|
|
} else { |
900
|
0
|
|
|
|
|
0
|
throw RDF::Trine::Error::CompilationError -text => "unknown type" |
901
|
|
|
|
|
|
|
} |
902
|
|
|
|
|
|
|
} |
903
|
1319
|
|
|
|
|
4270
|
$self->end_bulk_ops(); |
904
|
1319
|
|
|
|
|
4486
|
my $iter = $self->get_statements( $subj, $pred, undef, $graph ); |
905
|
1319
|
|
|
|
|
2514
|
my %nodes; |
906
|
1319
|
|
|
|
|
4336
|
while (my $st = $iter->next) { |
907
|
1351
|
|
|
|
|
6013
|
my $obj = $st->object; |
908
|
1351
|
100
|
|
|
|
3513
|
if (defined $type) { |
909
|
30
|
100
|
|
|
|
101
|
next unless $obj->$type; |
910
|
14
|
100
|
|
|
|
49
|
if ($options{language}) { |
|
|
100
|
|
|
|
|
|
911
|
3
|
|
|
|
|
8
|
my $lang = $obj->literal_value_language; |
912
|
3
|
100
|
66
|
|
|
18
|
next unless ($lang and $lang eq $options{language}); |
913
|
|
|
|
|
|
|
} elsif ($options{datatype}) { |
914
|
6
|
|
|
|
|
15
|
my $dt = $obj->literal_datatype; |
915
|
6
|
100
|
66
|
|
|
28
|
next unless ($dt and $dt eq $options{datatype}->uri_value); |
916
|
|
|
|
|
|
|
} |
917
|
|
|
|
|
|
|
} |
918
|
1329
|
|
|
|
|
5231
|
$nodes{ $obj->as_string } = $obj; |
919
|
|
|
|
|
|
|
} |
920
|
1319
|
100
|
|
|
|
3481
|
if (wantarray) { |
921
|
1315
|
|
|
|
|
10707
|
return values(%nodes); |
922
|
|
|
|
|
|
|
} else { |
923
|
4
|
|
|
|
|
22
|
return RDF::Trine::Iterator->new( [values(%nodes)] ); |
924
|
|
|
|
|
|
|
} |
925
|
|
|
|
|
|
|
} |
926
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
=item C<< objects_for_predicate_list ( $subject, @predicates ) >> |
928
|
|
|
|
|
|
|
|
929
|
|
|
|
|
|
|
Given the RDF::Trine::Node objects C<< $subject >> and C<< @predicates >>, |
930
|
|
|
|
|
|
|
finds all matching triples in the model with the specified subject and any |
931
|
|
|
|
|
|
|
of the given predicates, and returns a list of object values (in the partial |
932
|
|
|
|
|
|
|
order given by the ordering of C<< @predicates >>). |
933
|
|
|
|
|
|
|
|
934
|
|
|
|
|
|
|
=cut |
935
|
|
|
|
|
|
|
|
936
|
|
|
|
|
|
|
sub objects_for_predicate_list { |
937
|
94
|
|
|
94
|
1
|
187
|
my $self = shift; |
938
|
94
|
|
|
|
|
151
|
my $node = shift; |
939
|
94
|
|
|
|
|
211
|
my @preds = @_; |
940
|
94
|
|
|
|
|
255
|
$self->end_bulk_ops(); |
941
|
94
|
|
|
|
|
176
|
my @objects; |
942
|
94
|
|
|
|
|
185
|
foreach my $p (@preds) { |
943
|
137
|
|
|
|
|
344
|
my $iter = $self->get_statements( $node, $p ); |
944
|
137
|
|
|
|
|
398
|
while (my $s = $iter->next) { |
945
|
137
|
50
|
|
|
|
333
|
if (not(wantarray)) { |
946
|
0
|
|
|
|
|
0
|
return $s->object; |
947
|
|
|
|
|
|
|
} else { |
948
|
137
|
|
|
|
|
377
|
push( @objects, $s->object ); |
949
|
|
|
|
|
|
|
} |
950
|
|
|
|
|
|
|
} |
951
|
|
|
|
|
|
|
} |
952
|
94
|
|
|
|
|
316
|
return @objects; |
953
|
|
|
|
|
|
|
} |
954
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
=item C<< bounded_description ( $node ) >> |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
Returns an RDF::Trine::Iterator::Graph object over the bounded description |
958
|
|
|
|
|
|
|
triples for C<< $node >> (all triples resulting from a graph traversal starting |
959
|
|
|
|
|
|
|
with C<< node >> and stopping at non-blank nodes). |
960
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
=cut |
962
|
|
|
|
|
|
|
|
963
|
|
|
|
|
|
|
sub bounded_description { |
964
|
8
|
|
|
8
|
1
|
18
|
my $self = shift; |
965
|
8
|
|
|
|
|
15
|
my $node = shift; |
966
|
8
|
|
|
|
|
26
|
$self->end_bulk_ops(); |
967
|
8
|
|
|
|
|
18
|
my %seen; |
968
|
8
|
|
|
|
|
21
|
my @nodes = $node; |
969
|
8
|
|
|
|
|
14
|
my @statements; |
970
|
|
|
|
|
|
|
my $sub = sub { |
971
|
35
|
100
|
100
|
35
|
|
136
|
return if (not(@statements) and not(@nodes)); |
972
|
30
|
|
|
|
|
52
|
while (1) { |
973
|
33
|
100
|
|
|
|
71
|
if (not(@statements)) { |
974
|
20
|
|
|
|
|
121
|
my $l = Log::Log4perl->get_logger("rdf.trine.model"); |
975
|
20
|
100
|
|
|
|
1493
|
return unless (scalar(@nodes)); |
976
|
17
|
|
|
|
|
31
|
my $n = shift(@nodes); |
977
|
|
|
|
|
|
|
# warn "CBD handling node " . $n->sse . "\n"; |
978
|
17
|
100
|
|
|
|
55
|
next if ($seen{ $n->sse }); |
979
|
|
|
|
|
|
|
try { |
980
|
16
|
|
|
|
|
506
|
my $st = RDF::Trine::Statement->new( $n, map { variable($_) } qw(p o) ); |
|
32
|
|
|
|
|
84
|
|
981
|
16
|
|
|
|
|
73
|
my $pat = RDF::Trine::Pattern->new( $st ); |
982
|
16
|
|
|
|
|
61
|
my $sts = $self->get_pattern( $pat, undef, orderby => [ qw(p ASC o ASC) ] ); |
983
|
|
|
|
|
|
|
# my $sts = $stream->as_statements( qw(s p o) ); |
984
|
|
|
|
|
|
|
# my $sts = $self->get_statements( $n ); |
985
|
16
|
|
|
|
|
58
|
my @s = grep { not($seen{$_->{'o'}->sse}) } $sts->get_all; |
|
26
|
|
|
|
|
71
|
|
986
|
|
|
|
|
|
|
# warn "+ " . $_->as_string . "\n" for (@s); |
987
|
16
|
|
|
|
|
47
|
push(@statements, map { RDF::Trine::Statement->new($n, @{ $_ }{qw(p o)}) } @s); |
|
26
|
|
|
|
|
44
|
|
|
26
|
|
|
|
|
81
|
|
988
|
|
|
|
|
|
|
} catch RDF::Trine::Error::UnimplementedError with { |
989
|
0
|
|
|
|
|
0
|
$l->debug('[model] Ignored UnimplementedError in bounded_description: ' . $_[0]->{'-text'}); |
990
|
16
|
|
|
|
|
129
|
}; |
991
|
|
|
|
|
|
|
try { |
992
|
16
|
|
|
|
|
443
|
my $st = RDF::Trine::Statement->new( (map { variable($_) } qw(s p)), $n ); |
|
32
|
|
|
|
|
90
|
|
993
|
16
|
|
|
|
|
55
|
my $pat = RDF::Trine::Pattern->new( $st ); |
994
|
16
|
|
|
|
|
58
|
my $sts = $self->get_pattern( $pat, undef, orderby => [ qw(s ASC p ASC) ] ); |
995
|
|
|
|
|
|
|
# my $sts = $stream->as_statements( qw(s p o) ); |
996
|
|
|
|
|
|
|
# my $sts = $self->get_statements( undef, undef, $n ); |
997
|
16
|
|
100
|
|
|
57
|
my @s = grep { not($seen{$_->{'s'}->sse}) and not($_->{'s'}->equal($n)) } $sts->get_all; |
|
13
|
|
|
|
|
44
|
|
998
|
|
|
|
|
|
|
# warn "- " . $_->as_string . "\n" for (@s); |
999
|
16
|
|
|
|
|
71
|
push(@statements, map { RDF::Trine::Statement->new(@{ $_ }{qw(s p)}, $n) } @s); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
6
|
|
1000
|
|
|
|
|
|
|
} catch RDF::Trine::Error::UnimplementedError with { |
1001
|
0
|
|
|
|
|
0
|
$l->debug('[model] Ignored UnimplementedError in bounded_description: ' . $_[0]->{'-text'}); |
1002
|
16
|
|
|
|
|
419
|
}; |
1003
|
16
|
|
|
|
|
322
|
$seen{ $n->sse }++ |
1004
|
|
|
|
|
|
|
} |
1005
|
29
|
100
|
|
|
|
82
|
last if (scalar(@statements)); |
1006
|
|
|
|
|
|
|
} |
1007
|
27
|
50
|
|
|
|
73
|
return unless (scalar(@statements)); |
1008
|
27
|
|
|
|
|
44
|
my $st = shift(@statements); |
1009
|
27
|
100
|
66
|
|
|
73
|
if ($st->object->isa('RDF::Trine::Node::Blank') and not($seen{ $st->object->sse })) { |
1010
|
|
|
|
|
|
|
# warn "+ CBD pushing " . $st->object->sse . "\n"; |
1011
|
9
|
|
|
|
|
31
|
push(@nodes, $st->object); |
1012
|
|
|
|
|
|
|
} |
1013
|
27
|
50
|
66
|
|
|
72
|
if ($st->subject->isa('RDF::Trine::Node::Blank') and not($seen{ $st->subject->sse })) { |
1014
|
|
|
|
|
|
|
# warn "- CBD pushing " . $st->subject->sse . "\n"; |
1015
|
0
|
|
|
|
|
0
|
push(@nodes, $st->subject); |
1016
|
|
|
|
|
|
|
} |
1017
|
27
|
|
|
|
|
61
|
return $st; |
1018
|
8
|
|
|
|
|
49
|
}; |
1019
|
8
|
|
|
|
|
63
|
return RDF::Trine::Iterator::Graph->new( $sub ); |
1020
|
|
|
|
|
|
|
} |
1021
|
|
|
|
|
|
|
|
1022
|
|
|
|
|
|
|
=item C<< as_string >> |
1023
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
=cut |
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
sub as_string { |
1027
|
0
|
|
|
0
|
1
|
0
|
my $self = shift; |
1028
|
0
|
|
|
|
|
0
|
$self->end_bulk_ops(); |
1029
|
0
|
|
|
|
|
0
|
my $iter = $self->get_statements( undef, undef, undef, undef ); |
1030
|
0
|
|
|
|
|
0
|
my @rows; |
1031
|
0
|
|
|
|
|
0
|
my @names = qw[subject predicate object context]; |
1032
|
0
|
|
|
|
|
0
|
while (my $row = $iter->next) { |
1033
|
0
|
|
|
|
|
0
|
push(@rows, [map {$row->$_()->as_string} @names]); |
|
0
|
|
|
|
|
0
|
|
1034
|
|
|
|
|
|
|
} |
1035
|
0
|
|
|
|
|
0
|
my @rule = qw(- +); |
1036
|
0
|
|
|
|
|
0
|
my @headers = (\q"| "); |
1037
|
0
|
|
|
|
|
0
|
push(@headers, map { $_ => \q" | " } @names); |
|
0
|
|
|
|
|
0
|
|
1038
|
0
|
|
|
|
|
0
|
pop @headers; |
1039
|
0
|
|
|
|
|
0
|
push @headers => (\q" |"); |
1040
|
0
|
|
|
|
|
0
|
my $table = Text::Table->new(@names); |
1041
|
0
|
|
|
|
|
0
|
$table->rule(@rule); |
1042
|
0
|
|
|
|
|
0
|
$table->body_rule(@rule); |
1043
|
0
|
|
|
|
|
0
|
$table->load(@rows); |
1044
|
0
|
|
|
|
|
0
|
my $size = scalar(@rows); |
1045
|
|
|
|
|
|
|
return join('', |
1046
|
|
|
|
|
|
|
$table->rule(@rule), |
1047
|
|
|
|
|
|
|
$table->title, |
1048
|
|
|
|
|
|
|
$table->rule(@rule), |
1049
|
0
|
|
|
|
|
0
|
map({ $table->body($_) } 0 .. @rows), |
|
0
|
|
|
|
|
0
|
|
1050
|
|
|
|
|
|
|
$table->rule(@rule) |
1051
|
|
|
|
|
|
|
) . "$size statements\n"; |
1052
|
|
|
|
|
|
|
} |
1053
|
|
|
|
|
|
|
|
1054
|
|
|
|
|
|
|
sub _store { |
1055
|
16331
|
|
|
16331
|
|
25124
|
my $self = shift; |
1056
|
16331
|
|
|
|
|
45102
|
return $self->{store}; |
1057
|
|
|
|
|
|
|
} |
1058
|
|
|
|
|
|
|
|
1059
|
|
|
|
|
|
|
sub _debug { |
1060
|
0
|
|
|
0
|
|
|
my $self = shift; |
1061
|
0
|
|
|
|
|
|
my $warn = shift; |
1062
|
0
|
|
|
|
|
|
my $stream = $self->get_statements( undef, undef, undef, undef ); |
1063
|
0
|
|
|
|
|
|
my $l = Log::Log4perl->get_logger("rdf.trine.model"); |
1064
|
0
|
|
|
|
|
|
$l->debug( 'model statements:' ); |
1065
|
0
|
0
|
|
|
|
|
if ($warn) { |
1066
|
0
|
|
|
|
|
|
warn "Model $self:\n"; |
1067
|
|
|
|
|
|
|
} |
1068
|
0
|
|
|
|
|
|
my $count = 0; |
1069
|
0
|
|
|
|
|
|
while (my $s = $stream->next) { |
1070
|
0
|
|
|
|
|
|
$count++; |
1071
|
0
|
0
|
|
|
|
|
if ($warn) { |
1072
|
0
|
|
|
|
|
|
warn $s->as_string . "\n"; |
1073
|
|
|
|
|
|
|
} |
1074
|
0
|
|
|
|
|
|
$l->debug('[model]' . $s->as_string); |
1075
|
|
|
|
|
|
|
} |
1076
|
0
|
0
|
|
|
|
|
if ($warn) { |
1077
|
0
|
|
|
|
|
|
warn "$count statements\n"; |
1078
|
|
|
|
|
|
|
} |
1079
|
|
|
|
|
|
|
} |
1080
|
|
|
|
|
|
|
|
1081
|
|
|
|
|
|
|
1; |
1082
|
|
|
|
|
|
|
|
1083
|
|
|
|
|
|
|
__END__ |
1084
|
|
|
|
|
|
|
|
1085
|
|
|
|
|
|
|
=back |
1086
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
=head1 BUGS |
1088
|
|
|
|
|
|
|
|
1089
|
|
|
|
|
|
|
Please report any bugs or feature requests to through the GitHub web interface |
1090
|
|
|
|
|
|
|
at L<https://github.com/kasei/perlrdf/issues>. |
1091
|
|
|
|
|
|
|
|
1092
|
|
|
|
|
|
|
=head1 AUTHOR |
1093
|
|
|
|
|
|
|
|
1094
|
|
|
|
|
|
|
Gregory Todd Williams C<< <gwilliams@cpan.org> >> |
1095
|
|
|
|
|
|
|
|
1096
|
|
|
|
|
|
|
=head1 COPYRIGHT |
1097
|
|
|
|
|
|
|
|
1098
|
|
|
|
|
|
|
Copyright (c) 2006-2012 Gregory Todd Williams. This |
1099
|
|
|
|
|
|
|
program is free software; you can redistribute it and/or modify it under |
1100
|
|
|
|
|
|
|
the same terms as Perl itself. |
1101
|
|
|
|
|
|
|
|
1102
|
|
|
|
|
|
|
=cut |