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.017
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   452 use strict;
  68         164  
  68         1784  
34 68     68   329 use warnings;
  68         161  
  68         1773  
35 68     68   333 no warnings 'redefine';
  68         147  
  68         2033  
36 68     68   347 no warnings 'once';
  68         153  
  68         1713  
37 68     68   363 use base qw(RDF::Trine::Parser);
  68         169  
  68         4533  
38              
39 68     68   435 use URI;
  68         165  
  68         1264  
40 68     68   312 use Log::Log4perl;
  68         151  
  68         553  
41              
42 68     68   4130 use RDF::Trine qw(literal);
  68         169  
  68         2989  
43 68     68   409 use RDF::Trine::Statement;
  68         160  
  68         1301  
44 68     68   332 use RDF::Trine::Namespace;
  68         162  
  68         434  
45 68     68   362 use RDF::Trine::Node;
  68         164  
  68         2282  
46 68     68   363 use RDF::Trine::Error qw(:try);
  68         150  
  68         447  
47              
48 68     68   8703 use Scalar::Util qw(blessed looks_like_number);
  68         160  
  68         3095  
49 68     68   452 use JSON;
  68         156  
  68         590  
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   18249 $VERSION = '1.017';
55 68         202 $RDF::Trine::Parser::parser_names{ 'rdfjson' } = __PACKAGE__;
56 68         193 foreach my $ext (qw(json js)) {
57 136         397 $RDF::Trine::Parser::file_extensions{ $ext } = __PACKAGE__;
58             }
59 68         166 my $class = __PACKAGE__;
60 68         171 $RDF::Trine::Parser::canonical_media_types{ $class } = 'application/json';
61 68         164 foreach my $type (qw(application/json application/x-rdf+json)) {
62 136         45999 $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 4 my $class = shift;
74 2         6 my %args = @_;
75 2         5 my $prefix = '';
76 2 50       6 if (defined($args{ bnode_prefix })) {
77 0         0 $prefix = $args{ bnode_prefix };
78             } else {
79 2         10 $prefix = $class->new_bnode_prefix();
80             }
81 2         9 my $self = bless({
82             bindings => {},
83             bnode_id => 0,
84             bnode_prefix => $prefix,
85             @_
86             }, $class);
87 2         7 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 11 my $proto = shift;
99 2 50       8 my $self = blessed($proto) ? $proto : $proto->new();
100 2         4 my $uri = shift;
101 2 50 33     9 if (blessed($uri) and $uri->isa('RDF::Trine::Node::Resource')) {
102 0         0 $uri = $uri->uri_value;
103             }
104 2         4 my $input = shift;
105 2         4 my $model = shift;
106 2         4 my %args = @_;
107 2         4 my $context = $args{'context'};
108 2         4 my $opts = $args{'json_opts'};
109            
110             my $handler = sub {
111 4     4   7 my $st = shift;
112 4 50       11 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         14 $model->add_statement( $st );
117             }
118 2         10 };
119 2         6 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 4 my $self = shift;
132 2         3 my $uri = shift;
133 2         5 my $input = shift;
134 2         3 my $handler = shift;
135 2         4 my $opts = shift;
136            
137 2         4 my $index = eval { from_json($input, $opts) };
  2         9  
138 2 50       57 if ($@) {
139 0         0 throw RDF::Trine::Error::ParserError -text => "$@";
140             }
141            
142 2         7 foreach my $s (keys %$index) {
143             my $ts = ( $s =~ /^_:(.*)$/ ) ?
144 2 100       21 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         8  
148 2         8 my $tp = RDF::Trine::Node::Resource->new($p, $uri);
149            
150 2         4 foreach my $O (@{ $index->{$s}->{$p} }) {
  2         6  
151 4         8 my $to;
152            
153             # $O should be a hashref, but we can do a little error-correcting.
154 4 100       11 unless (ref $O) {
155 1 50       4 if ($O =~ /^_:/) {
    0          
    0          
156 1         4 $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       13 if (lc $O->{'type'} eq 'literal') {
167             $to = RDF::Trine::Node::Literal->new(
168 2         14 $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       13 RDF::Trine::Node::Resource->new($O->{'value'}, $uri);
173             }
174            
175 4 50 33     82 if ( $ts && $tp && $to ) {
      33        
176 4 50       28 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         24 my $st = RDF::Trine::Statement->new($ts, $tp, $to);
185 4         12 $handler->($st);
186             }
187             }
188             }
189             }
190            
191 2         15 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