File Coverage

blib/lib/RDF/Trine/Parser/RDFJSON.pm
Criterion Covered Total %
statement 98 111 88.2
branch 16 30 53.3
condition 3 12 25.0
subroutine 19 19 100.0
pod 3 3 100.0
total 139 175 79.4


line stmt bran cond sub pod time code
1             # RDF::Trine::Parser::RDFJSON
2             # -----------------------------------------------------------------------------
3              
4             =head1 NAME
5              
6             RDF::Trine::Parser::RDFJSON - RDF/JSON RDF Parser
7              
8             =head1 VERSION
9              
10             This document describes RDF::Trine::Parser::RDFJSON version 1.018
11              
12             =head1 SYNOPSIS
13              
14             use RDF::Trine::Parser;
15             my $parser = RDF::Trine::Parser->new( 'RDF/JSON' );
16             $parser->parse_into_model( $base_uri, $data, $model );
17              
18             =head1 DESCRIPTION
19              
20             ...
21              
22             =head1 METHODS
23              
24             Beyond the methods documented below, this class inherits methods from the
25             L<RDF::Trine::Parser> class.
26              
27             =over 4
28              
29             =cut
30              
31             package RDF::Trine::Parser::RDFJSON;
32              
33 68     68   444 use strict;
  68         157  
  68         1762  
34 68     68   349 use warnings;
  68         151  
  68         1733  
35 68     68   328 no warnings 'redefine';
  68         151  
  68         1986  
36 68     68   346 no warnings 'once';
  68         150  
  68         1634  
37 68     68   333 use base qw(RDF::Trine::Parser);
  68         150  
  68         4552  
38              
39 68     68   432 use URI;
  68         203  
  68         1312  
40 68     68   333 use Log::Log4perl;
  68         153  
  68         490  
41              
42 68     68   4306 use RDF::Trine qw(literal);
  68         165  
  68         2987  
43 68     68   394 use RDF::Trine::Statement;
  68         161  
  68         1326  
44 68     68   334 use RDF::Trine::Namespace;
  68         150  
  68         422  
45 68     68   384 use RDF::Trine::Node;
  68         163  
  68         2294  
46 68     68   401 use RDF::Trine::Error qw(:try);
  68         157  
  68         434  
47              
48 68     68   8965 use Scalar::Util qw(blessed looks_like_number);
  68         159  
  68         3178  
49 68     68   425 use JSON;
  68         166  
  68         583  
50              
51             our ($VERSION, $rdf, $xsd);
52             our ($r_boolean, $r_comment, $r_decimal, $r_double, $r_integer, $r_language, $r_lcharacters, $r_line, $r_nameChar_extra, $r_nameStartChar_minus_underscore, $r_scharacters, $r_ucharacters, $r_booltest, $r_nameStartChar, $r_nameChar, $r_prefixName, $r_qname, $r_resource_test, $r_nameChar_test);
53             BEGIN {
54 68     68   17843 $VERSION = '1.018';
55 68         194 $RDF::Trine::Parser::parser_names{ 'rdfjson' } = __PACKAGE__;
56 68         185 foreach my $ext (qw(json js)) {
57 136         362 $RDF::Trine::Parser::file_extensions{ $ext } = __PACKAGE__;
58             }
59 68         212 my $class = __PACKAGE__;
60 68         174 $RDF::Trine::Parser::canonical_media_types{ $class } = 'application/json';
61 68         169 foreach my $type (qw(application/json application/x-rdf+json)) {
62 136         45113 $RDF::Trine::Parser::media_types{ $type } = __PACKAGE__;
63             }
64             }
65              
66             =item C<< new >>
67              
68             Returns a new RDFJSON parser.
69              
70             =cut
71              
72             sub new {
73 2     2 1 6 my $class = shift;
74 2         9 my %args = @_;
75 2         5 my $prefix = '';
76 2 50       9 if (defined($args{ bnode_prefix })) {
77 0         0 $prefix = $args{ bnode_prefix };
78             } else {
79 2         15 $prefix = $class->new_bnode_prefix();
80             }
81 2         13 my $self = bless({
82             bindings => {},
83             bnode_id => 0,
84             bnode_prefix => $prefix,
85             @_
86             }, $class);
87 2         10 return $self;
88             }
89              
90             =item C<< parse_into_model ( $base_uri, $data, $model [, context => $context] ) >>
91              
92             Parses the bytes in C<< $data >>, using the given C<< $base_uri >>. For each RDF
93             statement parsed, will call C<< $model->add_statement( $statement ) >>.
94              
95             =cut
96              
97             sub parse_into_model {
98 2     2 1 14 my $proto = shift;
99 2 50       11 my $self = blessed($proto) ? $proto : $proto->new();
100 2         7 my $uri = shift;
101 2 50 33     10 if (blessed($uri) and $uri->isa('RDF::Trine::Node::Resource')) {
102 0         0 $uri = $uri->uri_value;
103             }
104 2         6 my $input = shift;
105 2         5 my $model = shift;
106 2         7 my %args = @_;
107 2         5 my $context = $args{'context'};
108 2         5 my $opts = $args{'json_opts'};
109            
110             my $handler = sub {
111 4     4   8 my $st = shift;
112 4 50       10 if ($context) {
113 0         0 my $quad = RDF::Trine::Statement::Quad->new( $st->nodes, $context );
114 0         0 $model->add_statement( $quad );
115             } else {
116 4         60 $model->add_statement( $st );
117             }
118 2         12 };
119 2         9 return $self->parse( $uri, $input, $handler, $opts );
120             }
121              
122             =item C<< parse ( $base_uri, $rdf, \&handler ) >>
123              
124             Parses the bytes in C<< $data >>, using the given C<< $base_uri >>. Calls the
125             C<< triple >> method for each RDF triple parsed. This method does nothing by
126             default, but can be set by using one of the default C<< parse_* >> methods.
127              
128             =cut
129              
130             sub parse {
131 2     2 1 5 my $self = shift;
132 2         5 my $uri = shift;
133 2         4 my $input = shift;
134 2         6 my $handler = shift;
135 2         4 my $opts = shift;
136            
137 2         7 my $index = eval { from_json($input, $opts) };
  2         12  
138 2 50       77 if ($@) {
139 0         0 throw RDF::Trine::Error::ParserError -text => "$@";
140             }
141            
142 2         10 foreach my $s (keys %$index) {
143             my $ts = ( $s =~ /^_:(.*)$/ ) ?
144 2 100       29 RDF::Trine::Node::Blank->new($self->{bnode_prefix} . $1) :
145             RDF::Trine::Node::Resource->new($s, $uri);
146            
147 2         5 foreach my $p (keys %{ $index->{$s} }) {
  2         9  
148 2         8 my $tp = RDF::Trine::Node::Resource->new($p, $uri);
149            
150 2         5 foreach my $O (@{ $index->{$s}->{$p} }) {
  2         7  
151 4         5 my $to;
152            
153             # $O should be a hashref, but we can do a little error-correcting.
154 4 100       13 unless (ref $O) {
155 1 50       5 if ($O =~ /^_:/) {
    0          
    0          
156 1         6 $O = { 'value'=>$O, 'type'=>'bnode' };
157             } elsif ($O =~ /^[a-z0-9._\+-]{1,12}:\S+$/i) {
158 0         0 $O = { 'value'=>$O, 'type'=>'uri' };
159             } elsif ($O =~ /^(.*)\@([a-z]{2})$/) {
160 0         0 $O = { 'value'=>$1, 'type'=>'literal', 'lang'=>$2 };
161             } else {
162 0         0 $O = { 'value'=>$O, 'type'=>'literal' };
163             }
164             }
165            
166 4 100       15 if (lc $O->{'type'} eq 'literal') {
167             $to = RDF::Trine::Node::Literal->new(
168 2         16 $O->{'value'}, $O->{'lang'}, $O->{'datatype'});
169             } else {
170             $to = ( $O->{'value'} =~ /^_:(.*)$/ ) ?
171             RDF::Trine::Node::Blank->new($self->{bnode_prefix} . $1) :
172 2 100       14 RDF::Trine::Node::Resource->new($O->{'value'}, $uri);
173             }
174            
175 4 50 33     91 if ( $ts && $tp && $to ) {
      33        
176 4 50       17 if ($self->{canonicalize}) {
177 0 0 0     0 if ($to->isa('RDF::Trine::Node::Literal') and $to->has_datatype) {
178 0         0 my $value = $to->literal_value;
179 0         0 my $dt = $to->literal_datatype;
180 0         0 my $canon = RDF::Trine::Node::Literal->canonicalize_literal_value( $value, $dt, 1 );
181 0         0 $to = literal( $canon, undef, $dt );
182             }
183             }
184 4         19 my $st = RDF::Trine::Statement->new($ts, $tp, $to);
185 4         10 $handler->($st);
186             }
187             }
188             }
189             }
190            
191 2         16 return;
192             }
193              
194              
195             1;
196              
197             __END__
198              
199             =back
200              
201             =head1 BUGS
202              
203             Please report any bugs or feature requests to through the GitHub web interface
204             at L<https://github.com/kasei/perlrdf/issues>.
205              
206             =head1 AUTHOR
207              
208             Toby Inkster <tobyink@cpan.org>
209             Gregory Williams <gwilliams@cpan.org>
210              
211             =head1 COPYRIGHT
212              
213             Copyright (c) 2006-2012 Gregory Todd Williams. This
214             program is free software; you can redistribute it and/or modify it under
215             the same terms as Perl itself.
216              
217             =cut