File Coverage

blib/lib/RDF/Trine/Serializer.pm
Criterion Covered Total %
statement 142 151 94.0
branch 20 20 100.0
condition 10 14 71.4
subroutine 32 34 94.1
pod 7 7 100.0
total 211 226 93.3


line stmt bran cond sub pod time code
1             # RDF::Trine::Serializer
2             # -----------------------------------------------------------------------------
3              
4             =head1 NAME
5              
6             RDF::Trine::Serializer - RDF Serializer class
7              
8             =head1 VERSION
9              
10             This document describes RDF::Trine::Serializer version 1.017
11              
12             =head1 SYNOPSIS
13              
14             use RDF::Trine::Serializer;
15              
16             =head1 DESCRIPTION
17              
18             The RDF::Trine::Serializer class provides an API for serializing RDF graphs
19             (via both model objects and graph iterators) to strings and files.
20              
21             =cut
22              
23             package RDF::Trine::Serializer;
24              
25 68     68   491 use strict;
  68         153  
  68         1649  
26 68     68   330 use warnings;
  68         136  
  68         1446  
27 68     68   309 no warnings 'redefine';
  68         144  
  68         1636  
28              
29 68     68   1893 use Data::Dumper;
  68         20929  
  68         2959  
30 68     68   122573 use HTTP::Negotiate qw(choose);
  68         23977  
  68         5691  
31              
32             our ($VERSION);
33             our %serializer_names;
34             our %format_uris;
35             our %media_types;
36             BEGIN {
37 68     68   1286 $VERSION = '1.017';
38             }
39              
40 68     68   23232 use RDF::Trine::Serializer::NQuads;
  68         259  
  68         1737  
41 68     68   23768 use RDF::Trine::Serializer::NTriples;
  68         180  
  68         1794  
42 68     68   25704 use RDF::Trine::Serializer::NTriples::Canonical;
  68         195  
  68         2146  
43 68     68   24878 use RDF::Trine::Serializer::RDFXML;
  68         197  
  68         2167  
44 68     68   24051 use RDF::Trine::Serializer::RDFJSON;
  68         202  
  68         1839  
45 68     68   429 use RDF::Trine::Serializer::Turtle;
  68         145  
  68         1385  
46 68     68   24031 use RDF::Trine::Serializer::TriG;
  68         193  
  68         2133  
47 68     68   23914 use RDF::Trine::Serializer::RDFPatch;
  68         202  
  68         46461  
48              
49              
50             =head1 METHODS
51              
52             =over 4
53              
54             =item C<< serializer_names >>
55              
56             Returns a list of valid serializer names for use as arguments to the serializer constructor.
57              
58             =cut
59              
60             sub serializer_names {
61 0     0 1 0 return keys %serializer_names;
62             }
63              
64             =item C<< new ( $serializer_name, %options ) >>
65              
66             Returns a new RDF::Trine::Serializer object for the serializer with the
67             specified name (e.g. "rdfxml" or "turtle"). If no serializer with the specified
68             name is found, throws a RDF::Trine::Error::SerializationError exception.
69              
70             The valid key-values used in C<< %options >> are specific to a particular
71             serializer implementation. For serializers that support namespace declarations
72             (to allow more concise serialization), use C<< namespaces => \%namespaces >> in
73             C<< %options >>, where the keys of C<< %namespaces >> are namespace names and
74             the values are (partial) URIs. For serializers that support base URI declarations,
75             use C<< base_uri => $base_uri >> .
76              
77             =cut
78              
79             sub new {
80 9     9 1 3538 my $class = shift;
81 9         17 my $name = shift;
82 9         20 my $key = lc($name);
83 9         29 $key =~ s/[^-a-z]//g;
84            
85 9 100       37 if (my $class = $serializer_names{ $key }) {
86 8         59 return $class->new( @_ );
87             } else {
88 1         16 throw RDF::Trine::Error::SerializationError -text => "No serializer known named $name";
89             }
90             }
91              
92             =item C<< negotiate ( request_headers => $request_headers, %options ) >>
93              
94             Returns a two-element list containing an appropriate media type and
95             RDF::Trine::Serializer object as decided by L<HTTP::Negotiate>. If
96             the C<< 'request_headers' >> key-value is supplied, the C<<
97             $request_headers >> is passed to C<< HTTP::Negotiate::choose >>. The
98             option C<< 'restrict' >>, set to a list of serializer names, can be
99             used to limit the serializers to choose from. Finally, an C<<'extend' >>
100             option can be set to a hashref that contains MIME-types
101             as keys and a custom variant as value. This will enable the user to
102             use this negotiator to return a type that isn't supported by any
103             serializers. The subsequent code will have to find out how to return a
104             representation. The rest of C<< %options >> is passed through to the
105             serializer constructor.
106              
107             =cut
108              
109             sub negotiate {
110 14     14 1 11219 my $class = shift;
111 14         42 my %options = @_;
112 14         31 my $headers = delete $options{ 'request_headers' };
113 14         27 my $restrict = delete $options{ 'restrict' };
114 14   100     62 my $extend = delete $options{ 'extend' } || {};
115 14         24 my %sclasses;
116 14 100 66     49 if (ref($restrict) && ref($restrict) eq 'ARRAY') {
117 3         13 $sclasses{ $serializer_names{$_} } = 1 for @$restrict;
118             } else {
119 11         66 %sclasses = reverse %serializer_names;
120             }
121 14         25 my @default_variants;
122 14         49 while (my($type, $sclass) = each(%media_types)) {
123 140 100       308 next unless $sclasses{$sclass};
124 124         162 my $qv;
125             # slightly prefer turtle as a readable format to others
126             # try hard to avoid using ntriples as 'text/plain' isn't very useful for conneg
127 124 100       258 if ($type eq 'text/turtle') {
    100          
128 14         24 $qv = 1.0;
129             } elsif ($type eq 'text/plain') {
130 11         18 $qv = 0.2;
131             } else {
132 99         140 $qv = 0.99;
133             }
134 124 100       286 $qv -= 0.01 if ($type =~ m#/x-#); # prefer non experimental media types
135 124 100       292 $qv -= 0.01 if ($type =~ m#^application/(?!rdf[+]xml)#); # prefer standard rdf/xml to other application/* formats
136 124         400 push(@default_variants, [$type, $qv, $type]);
137             }
138            
139 14         26 my %custom_thunks;
140             my @custom_variants;
141 14         44 while (my($type,$thunk) = each(%$extend)) {
142 3         7 push(@custom_variants, [$thunk, 1.0, $type]);
143 3         12 $custom_thunks{ $thunk } = [$type, $thunk];
144             }
145            
146             # remove variants with media types that are in custom_variants from @variants
147 14         27 my @variants = grep { not exists $extend->{ $_->[2] } } @default_variants;
  124         235  
148 14         19 push(@variants, @custom_variants);
149            
150 14         48 my $stype = choose( \@variants, $headers );
151 14 100 100     8332 if (defined($stype) and $custom_thunks{ $stype }) {
152 2         5 my $thunk = $stype;
153 2         5 my $type = $custom_thunks{ $stype }[0];
154 2         16 return ($type, $thunk);
155             }
156            
157 12 100 66     54 if (defined($stype) and my $sclass = $media_types{ $stype }) {
158 10         40 return ($stype, $sclass->new( %options ));
159             } else {
160 2         14 throw RDF::Trine::Error::SerializationError -text => "No appropriate serializer found for content-negotiation";
161             }
162             }
163              
164             =item C<< media_types >>
165              
166             Returns a list of media types appropriate for the format of the serializer.
167              
168             =cut
169              
170             sub media_types {
171 6     6 1 2178 my $self = shift;
172 6   33     21 my $class = ref($self) || $self;
173 6         12 my @list;
174 6         25 while (my($type, $sclass) = each(%media_types)) {
175 60 100       190 push(@list, $type) if ($sclass eq $class);
176             }
177 6         19 my @types = sort @list;
178 6         18 return @types;
179             }
180              
181             =item C<< serialize_model_to_file ( $fh, $model ) >>
182              
183             Serializes the C<< $model >>, printing the results to the supplied filehandle
184             C<<$fh>>.
185              
186             =item C<< serialize_model_to_string ( $model ) >>
187              
188             Serializes the C<< $model >>, returning the result as a string.
189              
190             =cut
191              
192             sub serialize_model_to_string {
193 13     13 1 181 my $self = shift;
194 13         26 my $model = shift;
195 13         26 my $string = '';
196 13     1   328 open( my $fh, '>:encoding(UTF-8)', \$string );
  1     1   9  
  1         3  
  1         8  
  1         1038  
  1         2  
  1         4  
197 13         1799 $self->serialize_model_to_file( $fh, $model );
198 11         153 close($fh);
199 11         63 return $string;
200             }
201              
202             =item C<< serialize_iterator_to_file ( $file, $iterator ) >>
203              
204             Serializes the statement objects produced by C<< $iterator >>, printing the
205             results to the supplied filehandle C<<$fh>>.
206              
207             Note that some serializers may not support the use of this method, or may
208             require the full materialization of the iterator in order to serialize it.
209             If materialization is required, available memeory may constrain the iterators
210             that can be serialized.
211              
212             =cut
213              
214             sub serialize_iterator_to_file {
215 0     0 1 0 my $self = shift;
216 0         0 my $fh = shift;
217 0         0 my $iter = shift;
218 0         0 my %args = @_;
219 0         0 my $model = RDF::Trine::Model->temporary_model;
220 0         0 while (my $st = $iter->next) {
221 0         0 $model->add_statement( $st );
222             }
223 0         0 return $self->serialize_model_to_file( $fh, $model );
224             }
225              
226              
227             =item C<< serialize_iterator_to_string ( $iterator ) >>
228              
229             Serializes the statement objects produced by C<< $iterator >>, returning the
230             result as a string. Note that the same constraints apply to this method as to
231             C<< serialize_iterator_to_file >>.
232              
233             =cut
234              
235             sub serialize_iterator_to_string {
236 7     7 1 47 my $self = shift;
237 7         13 my $iter = shift;
238 7         26 my $string = '';
239 7         116 open( my $fh, '>', \$string );
240 7         36 $self->serialize_iterator_to_file( $fh, $iter );
241 7         26 close($fh);
242 7         44 return $string;
243             }
244              
245              
246              
247              
248             =back
249              
250             =cut
251              
252             package RDF::Trine::Serializer::FileSink;
253              
254 68     68   542 use strict;
  68         165  
  68         1388  
255 68     68   335 use warnings;
  68         171  
  68         5886  
256              
257             =begin private
258              
259             =head1 NAME
260              
261             RDF::Trine::Serializer::FileSink
262              
263             =head1 METHODS
264              
265             =over 4
266              
267             =cut
268              
269             =item C<< new ( $fh ) >>
270              
271             Returns a new serializer sink object backed by a filehandle.
272              
273             =cut
274              
275             sub new {
276 1     1   3 my $class = shift;
277 1         2 my $fh = shift;
278 1         5 return bless([$fh],$class);
279             }
280              
281             =item C<< emit ( $data ) >>
282              
283             Write the C<< $data >> to the sink.
284              
285             =cut
286              
287             sub emit {
288 16     16   26 my $self = shift;
289 16         24 my $data = shift;
290 16         25 print {$self->[0]} $data;
  16         57  
291             }
292              
293             =back
294              
295             =cut
296              
297             package RDF::Trine::Serializer::StringSink;
298              
299 68     68   406 use strict;
  68         162  
  68         1327  
300 68     68   326 use warnings;
  68         130  
  68         1609  
301 68     68   324 use Encode;
  68         169  
  68         11722  
302              
303             =head1 NAME
304              
305             RDF::Trine::Serializer::StringSink
306              
307             =head1 METHODS
308              
309             =over 4
310              
311             =cut
312              
313             =item C<< new () >>
314              
315             Returns a new serializer sink object backed by a string.
316              
317             =cut
318              
319             sub new {
320 42     42   85 my $class = shift;
321 42         177 my $string = decode_utf8("");
322 42         1408 return bless(\$string,$class);
323             }
324              
325             =item C<< emit ( $data ) >>
326              
327             Write the C<< $data >> to the sink.
328              
329             =cut
330              
331             sub emit {
332 767     767   1204 my $self = shift;
333 767         1380 my $data = shift;
334 767         2089 $$self .= $data;
335             }
336              
337             =item C<< prepend ( $data ) >>
338              
339             Prepend the C<< $data >> to the underlying string.
340              
341             =cut
342              
343             sub prepend {
344 10     10   20 my $self = shift;
345 10         28 my $data = shift;
346 10         74 $$self = $data . $$self;
347             }
348              
349             =item C<< string () >>
350              
351             Returns the string value of all data written to the sink.
352              
353             =cut
354              
355             sub string {
356 47     47   108 my $self = shift;
357 47         702 return $$self;
358             }
359              
360             =back
361              
362             =end private
363              
364             =cut
365              
366             1;
367              
368             __END__
369              
370             =head1 BUGS
371              
372             Please report any bugs or feature requests to through the GitHub web interface
373             at L<https://github.com/kasei/perlrdf/issues>.
374              
375             =head1 AUTHOR
376              
377             Gregory Todd Williams C<< <gwilliams@cpan.org> >>
378              
379             =head1 COPYRIGHT
380              
381             Copyright (c) 2006-2012 Gregory Todd Williams. This
382             program is free software; you can redistribute it and/or modify it under
383             the same terms as Perl itself.
384              
385             =cut