File Coverage

blib/lib/AtteanX/Parser/JSONLD.pm
Criterion Covered Total %
statement 77 112 68.7
branch 6 16 37.5
condition 1 3 33.3
subroutine 24 31 77.4
pod 14 17 82.3
total 122 179 68.1


line stmt bran cond sub pod time code
1 1     1   45300 use v5.14;
  1         4  
2 1     1   6 use warnings;
  1         2  
  1         46  
3              
4             =head1 NAME
5              
6             AtteanX::Parser::JSONLD - JSONLD Parser
7              
8             =head1 VERSION
9              
10             This document describes AtteanX::Parser::JSONLD version 0.001
11              
12             =head1 SYNOPSIS
13              
14             use Attean;
15             my $parser = Attean->get_parser('JSONLD')->new();
16             $parser->parse_cb_from_io( $fh );
17              
18             =head1 DESCRIPTION
19              
20             This module implements a JSON-LD 1.11 RDF parser for L<Attean>.
21              
22             =head1 ROLES
23              
24             This class consumes the following roles:
25              
26             =over 4
27              
28             =item * L<Attean::API::MixedStatementParser>
29              
30             =item * L<Attean::API::AbbreviatingParser>
31              
32             =item * L<Attean::API::PullParser>
33              
34             =back
35              
36             =head1 METHODS
37              
38             =over 4
39              
40             =cut
41              
42             package AtteanX::Parser::JSONLD::Handler {
43 1     1   7 use v5.18;
  1         4  
44 1     1   4 use autodie;
  1         2  
  1         8  
45 1     1   4429 use Moo;
  1         2  
  1         9  
46 1     1   483 use Attean::RDF;
  1         2  
  1         17  
47 1     1   743 use Encode qw(decode_utf8 encode_utf8);
  1         2  
  1         59  
48             extends 'JSONLD';
49 1     1   5 use namespace::clean;
  1         2  
  1         10  
50            
51             sub default_graph {
52 3     3 1 744 return iri('tag:gwilliams@cpan.org,2010-01-01:Attean:DEFAULT');
53             }
54              
55             sub add_quad {
56 1     1 1 1345 my $self = shift;
57 1         3 my $quad = shift;
58 1         1 my $ds = shift;
59 1         21 $ds->add_quad($quad);
60             }
61              
62             sub new_dataset {
63 2     2 1 3093 my $self = shift;
64 2         14 my $store = Attean->get_store('Memory')->new();
65 2         40437 return $store;
66             }
67            
68             sub new_triple {
69 0     0 1 0 my $self = shift;
70 0         0 foreach my $v (@_) {
71 0 0       0 Carp::confess "not a term object" unless (ref($v));
72             }
73 0         0 return triple(@_);
74             }
75            
76             sub new_quad {
77 1     1 1 242 my $self = shift;
78 1         4 foreach my $v (@_) {
79 4 50 33     57 unless (ref($v) and $v->does('Attean::API::Term')) {
80             # warn "not a term object: $v";
81 0         0 return;
82             }
83             }
84 1         15 return quad(@_);
85             }
86            
87             sub skolem_prefix {
88 1     1 0 2 my $self = shift;
89 1         2 return 'tag:gwilliams@cpan.org,2019-12:JSONLD:skolem:';
90             }
91             sub new_graphname {
92 0     0 1 0 my $self = shift;
93 0         0 my $value = shift;
94 0 0       0 if ($value =~ /^_:(.+)$/) {
95 0         0 $value = $self->skolem_prefix() . $1;
96             }
97 0         0 return $self->new_iri($value);
98             }
99              
100             sub new_iri {
101 2     2 1 5404 my $self = shift;
102 2         6 return iri(shift);
103             }
104            
105             sub new_blank {
106 0     0 1 0 my $self = shift;
107 0         0 return blank(@_);
108             }
109            
110             sub new_lang_literal {
111 0     0 1 0 my $self = shift;
112 0         0 my $value = shift;
113 0         0 my $lang = shift;
114 0         0 return langliteral($value, $lang);
115             }
116            
117             sub canonical_json {
118 0     0 0 0 my $class = shift;
119 0         0 my $value = shift;
120 0         0 my $j = JSON->new->utf8->allow_nonref->canonical(1);
121 0         0 my $v = $j->decode($value);
122 0         0 return $j->encode($v);
123             }
124              
125             sub new_dt_literal {
126 1     1 1 364 my $self = shift;
127 1         2 my $value = shift;
128 1         2 my $dt = shift;
129 1 50       4 if ($dt eq 'http://www.w3.org/1999/02/22-rdf-syntax-ns#JSON') {
130 0         0 $value = decode_utf8($self->canonical_json(encode_utf8($value)));
131             }
132 1         5 return dtliteral($value, $dt);
133             }
134             }
135              
136             package AtteanX::Parser::JSONLD {
137 1     1   4221 use utf8;
  1         2  
  1         7  
138            
139             our $VERSION = '0.001';
140              
141 1     1   35 use Attean;
  1         2  
  1         7  
142 1     1   691 use JSON;
  1         6604  
  1         4  
143 1     1   861 use JSONLD;
  1         61068  
  1         40  
144 1     1   8 use Moo;
  1         2  
  1         6  
145            
146             =item C<< canonical_media_type >>
147              
148             Returns the canonical media type for JSON-LD: application/ld+json.
149              
150             =cut
151              
152 1     1 1 3656 sub canonical_media_type { return "application/ld+json" }
153              
154             =item C<< media_types >>
155              
156             Returns a list of media types that may be parsed with the JSON-LD parser:
157             application/ld+json.
158              
159             =cut
160              
161             sub media_types {
162 0     0 1 0 return [qw(application/ld+json)];
163             }
164            
165             =item C<< file_extensions >>
166              
167             Returns a list of file extensions that may be parsed with the parser.
168              
169             =cut
170              
171 1     1 1 4 sub file_extensions { return [qw(jsonld json)] }
172            
173             with 'Attean::API::MixedStatementParser';
174             with 'Attean::API::AbbreviatingParser';
175             with 'Attean::API::PullParser';
176              
177              
178             =item C<< parse_iter_from_io( $fh ) >>
179              
180             Returns an iterator of L<Attean::API::Binding> objects that result from parsing
181             the data read from the L<IO::Handle> object C<< $fh >>.
182              
183             =cut
184              
185             sub parse_iter_from_io {
186 0     0 1 0 my $self = shift;
187 0         0 my $fh = shift;
188 0         0 my $bytes = do { local($/); <$fh> };
  0         0  
  0         0  
189 0         0 return $self->parse_iter_from_bytes($bytes);
190             }
191              
192             =item C<< parse_cb_from_bytes( $data ) >>
193              
194             Calls the C<< $parser->handler >> function once for each
195             L<Attean::API::Binding> object that result from parsing
196             the data read from the UTF-8 encoded byte string C<< $data >>.
197              
198             =cut
199              
200             sub parse_iter_from_bytes {
201 2     2 0 94080 my $self = shift;
202 2         6 my $bytes = shift;
203 2         28 my $j = JSON->new();
204 2         25 my $data = $j->decode($bytes);
205            
206 2         4 my %args;
207 2 50       13 if ($self->has_base) {
208 0         0 $args{base_iri} = $self->base;
209             }
210 2         34 my $jld = AtteanX::Parser::JSONLD::Handler->new(%args);
211 2         4766 my $qiter = $jld->to_rdf($data)->get_quads();
212              
213 2         9444 my $default_graph = $jld->default_graph();
214             my $iter = Attean::CodeIterator->new(generator => sub {
215 3     3   2685 my $q = $qiter->next;
216 3 100       405 return unless ($q);
217 1         4 my $g = $q->graph;
218 1         5 my $prefix = $jld->skolem_prefix();
219 1 50       6 if ($g->equals($default_graph)) {
    0          
220 1         15 return $q->as_triple;
221             } elsif (substr($g->value, 0, length($prefix)) eq $prefix) {
222 0         0 my $gb = $jld->new_blank(substr($g->value, length($prefix)));
223 0         0 my @terms = $q->values;
224 0         0 $terms[3] = $gb;
225 0         0 return $jld->new_quad(@terms);
226             } else {
227 0         0 return $q;
228             }
229 2         4188 }, item_type => 'Attean::API::TripleOrQuad')->materialize;
230 2         2978 return $iter;
231             }
232             }
233              
234             1;
235              
236             __END__
237              
238             =back
239              
240             =head1 BUGS
241              
242             Please report any bugs or feature requests to through the GitHub web interface
243             at L<https://github.com/kasei/atteanx-parser-jsonld/issues>.
244              
245             =head1 AUTHOR
246              
247             Gregory Todd Williams C<< <gwilliams@cpan.org> >>
248              
249             =head1 COPYRIGHT
250              
251             Copyright (c) 2020--2020 Gregory Todd Williams. This
252             program is free software; you can redistribute it and/or modify it under
253             the same terms as Perl itself.
254              
255             =cut