| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | # RDF::Trine::Parser::Turtle | 
| 2 |  |  |  |  |  |  | # ----------------------------------------------------------------------------- | 
| 3 |  |  |  |  |  |  |  | 
| 4 |  |  |  |  |  |  | =head1 NAME | 
| 5 |  |  |  |  |  |  |  | 
| 6 |  |  |  |  |  |  | RDF::Trine::Parser::Turtle - Turtle RDF Parser | 
| 7 |  |  |  |  |  |  |  | 
| 8 |  |  |  |  |  |  | =head1 VERSION | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | This document describes RDF::Trine::Parser::Turtle version 1.018 | 
| 11 |  |  |  |  |  |  |  | 
| 12 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | use RDF::Trine::Parser; | 
| 15 |  |  |  |  |  |  | my $parser	= RDF::Trine::Parser->new( 'turtle' ); | 
| 16 |  |  |  |  |  |  | $parser->parse_into_model( $base_uri, $data, $model ); | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | This module implements a parser for the Turtle RDF format. | 
| 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::Turtle; | 
| 32 |  |  |  |  |  |  |  | 
| 33 | 68 |  |  | 68 |  | 460 | use utf8; | 
|  | 68 |  |  |  |  | 169 |  | 
|  | 68 |  |  |  |  | 488 |  | 
| 34 | 68 |  |  | 68 |  | 3054 | use 5.010; | 
|  | 68 |  |  |  |  | 308 |  | 
| 35 | 68 |  |  | 68 |  | 344 | use strict; | 
|  | 68 |  |  |  |  | 161 |  | 
|  | 68 |  |  |  |  | 1279 |  | 
| 36 | 68 |  |  | 68 |  | 410 | use warnings; | 
|  | 68 |  |  |  |  | 200 |  | 
|  | 68 |  |  |  |  | 2009 |  | 
| 37 | 68 |  |  | 68 |  | 402 | use Scalar::Util qw(blessed); | 
|  | 68 |  |  |  |  | 192 |  | 
|  | 68 |  |  |  |  | 3495 |  | 
| 38 | 68 |  |  | 68 |  | 401 | use base qw(RDF::Trine::Parser); | 
|  | 68 |  |  |  |  | 180 |  | 
|  | 68 |  |  |  |  | 4803 |  | 
| 39 | 68 |  |  | 68 |  | 445 | use RDF::Trine::Error qw(:try); | 
|  | 68 |  |  |  |  | 176 |  | 
|  | 68 |  |  |  |  | 501 |  | 
| 40 | 68 |  |  | 68 |  | 9206 | use Data::Dumper; | 
|  | 68 |  |  |  |  | 172 |  | 
|  | 68 |  |  |  |  | 2846 |  | 
| 41 | 68 |  |  | 68 |  | 24813 | use RDF::Trine::Parser::Turtle::Constants; | 
|  | 68 |  |  |  |  | 179 |  | 
|  | 68 |  |  |  |  | 6725 |  | 
| 42 | 68 |  |  | 68 |  | 27257 | use RDF::Trine::Parser::Turtle::Lexer; | 
|  | 68 |  |  |  |  | 313 |  | 
|  | 68 |  |  |  |  | 4047 |  | 
| 43 | 68 |  |  | 68 |  | 40179 | use RDF::Trine::Parser::Turtle::Token; | 
|  | 68 |  |  |  |  | 298 |  | 
|  | 68 |  |  |  |  | 11219 |  | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | our $VERSION; | 
| 46 |  |  |  |  |  |  | BEGIN { | 
| 47 | 68 |  |  | 68 |  | 261 | $VERSION				= '1.018'; | 
| 48 | 68 |  |  |  |  | 183 | foreach my $ext (qw(ttl)) { | 
| 49 | 68 |  |  |  |  | 337 | $RDF::Trine::Parser::file_extensions{ $ext }	= __PACKAGE__; | 
| 50 |  |  |  |  |  |  | } | 
| 51 | 68 |  |  |  |  | 206 | $RDF::Trine::Parser::parser_names{ 'turtle' }	= __PACKAGE__; | 
| 52 | 68 |  |  |  |  | 169 | my $class										= __PACKAGE__; | 
| 53 | 68 |  |  |  |  | 213 | $RDF::Trine::Parser::encodings{ $class }		= 'utf8'; | 
| 54 | 68 |  |  |  |  | 203 | $RDF::Trine::Parser::format_uris{ 'http://www.w3.org/ns/formats/Turtle' }	= __PACKAGE__; | 
| 55 | 68 |  |  |  |  | 177 | $RDF::Trine::Parser::canonical_media_types{ $class }	= 'text/turtle'; | 
| 56 | 68 |  |  |  |  | 162 | foreach my $type (qw(application/x-turtle application/turtle text/turtle)) { | 
| 57 | 204 |  |  |  |  | 148743 | $RDF::Trine::Parser::media_types{ $type }	= __PACKAGE__; | 
| 58 |  |  |  |  |  |  | } | 
| 59 |  |  |  |  |  |  | } | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  | my $rdf	= RDF::Trine::Namespace->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#'); | 
| 62 |  |  |  |  |  |  | my $xsd	= RDF::Trine::Namespace->new('http://www.w3.org/2001/XMLSchema#'); | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | =item C<< new ( [ namespaces => $map ] ) >> | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | Returns a new Turtle parser. | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | =cut | 
| 69 |  |  |  |  |  |  |  | 
| 70 |  |  |  |  |  |  | sub new { | 
| 71 | 386 |  |  | 386 | 1 | 141411 | my $class	= shift; | 
| 72 | 386 |  |  |  |  | 1239 | my %args	= @_; | 
| 73 | 386 |  |  |  |  | 2160 | return bless({ %args, stack => [] }, $class); | 
| 74 |  |  |  |  |  |  | } | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | =item C<< parse ( $base_uri, $rdf, \&handler ) >> | 
| 77 |  |  |  |  |  |  |  | 
| 78 |  |  |  |  |  |  | Parses the bytes in C<< $data >>, using the given C<< $base_uri >>. Calls the | 
| 79 |  |  |  |  |  |  | C<< triple >> method for each RDF triple parsed. This method does nothing by | 
| 80 |  |  |  |  |  |  | default, but can be set by using one of the default C<< parse_* >> methods. | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  | =cut | 
| 83 |  |  |  |  |  |  |  | 
| 84 |  |  |  |  |  |  | sub parse { | 
| 85 | 250 |  |  | 250 | 1 | 1008 | my $self	= shift; | 
| 86 | 250 |  |  |  |  | 893 | local($self->{baseURI})	= shift; | 
| 87 | 250 |  |  |  |  | 563 | my $string				= shift; | 
| 88 |  |  |  |  |  |  | # 	warn 'parse() content: ' . Dumper($string);	# XXX | 
| 89 | 250 |  |  |  |  | 679 | local($self->{handle_triple}) = shift; | 
| 90 | 250 |  |  |  |  | 1968 | require Encode; | 
| 91 | 250 |  |  |  |  | 1171 | $string = Encode::encode("utf-8", $string); | 
| 92 | 250 |  |  | 12 |  | 20693 | open(my $fh, '<:encoding(UTF-8)', \$string); | 
|  | 12 |  |  | 10 |  | 71 |  | 
|  | 12 |  |  |  |  | 26 |  | 
|  | 12 |  |  |  |  | 76 |  | 
|  | 10 |  |  |  |  | 7583 |  | 
|  | 10 |  |  |  |  | 24 |  | 
|  | 10 |  |  |  |  | 47 |  | 
| 93 | 250 |  |  |  |  | 30655 | my $l	= RDF::Trine::Parser::Turtle::Lexer->new($fh); | 
| 94 | 250 |  |  |  |  | 947 | $self->_parse($l); | 
| 95 |  |  |  |  |  |  | } | 
| 96 |  |  |  |  |  |  |  | 
| 97 |  |  |  |  |  |  | =item C<< parse_file ( $base_uri, $fh, $handler ) >> | 
| 98 |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  | Parses all data read from the filehandle or file C<< $fh >>, using the given | 
| 100 |  |  |  |  |  |  | C<< $base_uri >>. If C<< $fh >> is a filename, this method can guess the | 
| 101 |  |  |  |  |  |  | associated parse. For each RDF statement parses C<< $handler >> is called. | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | =cut | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | sub parse_file { | 
| 106 | 137 |  |  | 137 | 1 | 309 | my $self	= shift; | 
| 107 | 137 |  |  |  |  | 482 | local($self->{baseURI})	= shift; | 
| 108 | 137 |  |  |  |  | 283 | my $fh		= shift; | 
| 109 | 137 |  |  |  |  | 405 | local($self->{handle_triple}) = shift; | 
| 110 |  |  |  |  |  |  |  | 
| 111 | 137 | 100 |  |  |  | 441 | unless (ref($fh)) { | 
| 112 | 5 |  |  |  |  | 8 | my $filename	= $fh; | 
| 113 | 5 |  |  |  |  | 9 | undef $fh; | 
| 114 | 5 | 50 |  |  |  | 20 | unless ($self->can('parse')) { | 
| 115 | 0 |  |  |  |  | 0 | my $pclass = $self->guess_parser_by_filename( $filename ); | 
| 116 | 0 | 0 | 0 |  |  | 0 | $self = $pclass->new() if ($pclass and $pclass->can('new')); | 
| 117 |  |  |  |  |  |  | } | 
| 118 | 5 | 50 |  |  |  | 151 | open( $fh, '<:encoding(UTF-8)', $filename ) or throw RDF::Trine::Error::ParserError -text => $!; | 
| 119 |  |  |  |  |  |  | } | 
| 120 |  |  |  |  |  |  |  | 
| 121 | 137 |  |  |  |  | 5831 | my $l	= RDF::Trine::Parser::Turtle::Lexer->new($fh); | 
| 122 | 137 |  |  |  |  | 544 | $self->_parse($l); | 
| 123 |  |  |  |  |  |  | } | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | =item C<< parse_node ( $string, $base, [ token => \$token ] ) >> | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | Returns the RDF::Trine::Node object corresponding to the node whose N-Triples | 
| 128 |  |  |  |  |  |  | serialization is found at the beginning of C<< $string >>. | 
| 129 |  |  |  |  |  |  | If a reference to C<< $token >> is given, it is dereferenced and set to the | 
| 130 |  |  |  |  |  |  | RDF::Trine::Parser::Turtle::Token tokenizer object, allowing access to information such | 
| 131 |  |  |  |  |  |  | as the token's position in the input string. | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | =cut | 
| 134 |  |  |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | sub parse_node { | 
| 136 | 24 |  |  | 24 | 1 | 39 | my $self	= shift; | 
| 137 | 24 |  |  |  |  | 40 | my $string	= shift; | 
| 138 | 24 |  |  |  |  | 66 | local($self->{baseURI})	= shift; | 
| 139 | 24 |  |  |  |  | 58 | my %args	= @_; | 
| 140 | 24 |  |  |  |  | 343 | open(my $fh, '<:encoding(UTF-8)', \$string); | 
| 141 | 24 |  |  |  |  | 2861 | my $l	= RDF::Trine::Parser::Turtle::Lexer->new($fh); | 
| 142 | 24 |  |  |  |  | 71 | my $t = $self->_next_nonws($l); | 
| 143 | 24 | 50 |  |  |  | 64 | return unless ($t); | 
| 144 | 24 |  |  |  |  | 71 | my $node	= $self->_term($l, $t); | 
| 145 | 24 |  |  |  |  | 45 | my $token_ref	= $args{token}; | 
| 146 | 24 | 50 | 33 |  |  | 119 | if (defined($token_ref) and ref($token_ref)) { | 
| 147 | 24 |  |  |  |  | 47 | $$token_ref	= $t; | 
| 148 |  |  |  |  |  |  | } | 
| 149 | 24 |  |  |  |  | 671 | return $node; | 
| 150 |  |  |  |  |  |  | } | 
| 151 |  |  |  |  |  |  |  | 
| 152 |  |  |  |  |  |  | sub _parse { | 
| 153 | 387 |  |  | 387 |  | 759 | my $self	= shift; | 
| 154 | 387 |  |  |  |  | 731 | my $l		= shift; | 
| 155 | 387 |  |  |  |  | 1564 | $l->check_for_bom; | 
| 156 | 387 | 100 |  |  |  | 1315 | unless (exists($self->{map})) { | 
| 157 | 377 |  |  |  |  | 2809 | $self->{map}	= RDF::Trine::NamespaceMap->new(); | 
| 158 |  |  |  |  |  |  | } | 
| 159 | 387 |  |  |  |  | 1361 | while (my $t = $self->_next_nonws($l)) { | 
| 160 | 1062 |  |  |  |  | 3657 | $self->_statement($l, $t); | 
| 161 |  |  |  |  |  |  | } | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | ################################################################################ | 
| 165 |  |  |  |  |  |  |  | 
| 166 |  |  |  |  |  |  | sub _unget_token { | 
| 167 | 3749 |  |  | 3749 |  | 6663 | my $self	= shift; | 
| 168 | 3749 |  |  |  |  | 5874 | my $t		= shift; | 
| 169 | 3749 |  |  |  |  | 5528 | push(@{ $self->{ stack } }, $t); | 
|  | 3749 |  |  |  |  | 8657 |  | 
| 170 |  |  |  |  |  |  | } | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  | sub _next_nonws { | 
| 173 | 13365 |  |  | 13365 |  | 20549 | my $self	= shift; | 
| 174 | 13365 |  |  |  |  | 19753 | my $l		= shift; | 
| 175 | 13365 | 100 |  |  |  | 19201 | if (scalar(@{ $self->{ stack } })) { | 
|  | 13365 |  |  |  |  | 35023 |  | 
| 176 | 3749 |  |  |  |  | 5879 | return pop(@{ $self->{ stack } }); | 
|  | 3749 |  |  |  |  | 8937 |  | 
| 177 |  |  |  |  |  |  | } | 
| 178 | 9616 |  |  |  |  | 14924 | while (1) { | 
| 179 | 9616 |  |  |  |  | 28622 | my $t	= $l->get_token; | 
| 180 | 9583 | 100 |  |  |  | 33685 | return unless ($t); | 
| 181 | 9282 |  |  |  |  | 232016 | my $type = $t->type; | 
| 182 |  |  |  |  |  |  | # 		next if ($type == WS or $type == COMMENT); | 
| 183 |  |  |  |  |  |  | # 		warn decrypt_constant($type) . "\n"; | 
| 184 | 9282 |  |  |  |  | 23499 | return $t; | 
| 185 |  |  |  |  |  |  | } | 
| 186 |  |  |  |  |  |  | } | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  | sub _get_token_type { | 
| 189 | 1538 |  |  | 1538 |  | 2972 | my $self	= shift; | 
| 190 | 1538 |  |  |  |  | 2700 | my $l		= shift; | 
| 191 | 1538 |  |  |  |  | 2752 | my $type	= shift; | 
| 192 | 1538 |  |  |  |  | 3812 | my $t		= $self->_next_nonws($l); | 
| 193 | 1537 | 100 |  |  |  | 4200 | unless ($t) { | 
| 194 | 3 |  |  |  |  | 13 | $l->_throw_error(sprintf("Expecting %s but got EOF", decrypt_constant($type))); | 
| 195 | 0 |  |  |  |  | 0 | return; | 
| 196 |  |  |  |  |  |  | } | 
| 197 | 1534 | 100 |  |  |  | 37540 | unless ($t->type eq $type) { | 
| 198 | 12 |  |  |  |  | 50 | $self->_throw_error(sprintf("Expecting %s but got %s", decrypt_constant($type), decrypt_constant($t->type)), $t, $l); | 
| 199 |  |  |  |  |  |  | } | 
| 200 | 1522 |  |  |  |  | 20547 | return $t; | 
| 201 |  |  |  |  |  |  | } | 
| 202 |  |  |  |  |  |  |  | 
| 203 |  |  |  |  |  |  | sub _statement { | 
| 204 | 1039 |  |  | 1039 |  | 2085 | my $self	= shift; | 
| 205 | 1039 |  |  |  |  | 1888 | my $l		= shift; | 
| 206 | 1039 |  |  |  |  | 1819 | my $t		= shift; | 
| 207 | 1039 |  |  |  |  | 25346 | my $type	= $t->type; | 
| 208 |  |  |  |  |  |  | # 		when (WS) {} | 
| 209 | 1039 | 100 | 100 |  |  | 8475 | if ($type == PREFIX or $type == SPARQLPREFIX) { | 
|  |  | 100 | 100 |  |  |  |  | 
| 210 | 245 |  |  |  |  | 693 | $t	= $self->_get_token_type($l, PREFIXNAME); | 
| 211 | 241 |  |  |  |  | 826 | my $name	= $t->value; | 
| 212 | 241 |  |  |  |  | 1002 | $name		=~ s/:$//; | 
| 213 | 241 |  |  |  |  | 774 | $t	= $self->_get_token_type($l, IRI); | 
| 214 | 239 |  |  |  |  | 6231 | my $r	= RDF::Trine::Node::Resource->new($t->value, $self->{baseURI}); | 
| 215 | 239 |  |  |  |  | 868 | my $iri	= $r->uri_value; | 
| 216 | 239 | 100 |  |  |  | 796 | if ($type == PREFIX) { | 
| 217 | 236 |  |  |  |  | 777 | $t	= $self->_get_token_type($l, DOT); | 
| 218 |  |  |  |  |  |  | # 			$t	= $self->_next_nonws($l); | 
| 219 |  |  |  |  |  |  | # 			if ($t and $t->type != DOT) { | 
| 220 |  |  |  |  |  |  | # 				$self->_unget_token($t); | 
| 221 |  |  |  |  |  |  | # 			} | 
| 222 |  |  |  |  |  |  | } | 
| 223 | 239 |  |  |  |  | 6190 | $self->{map}->add_mapping( $name => $iri ); | 
| 224 | 239 | 100 |  |  |  | 3183 | if (my $ns = $self->{namespaces}) { | 
| 225 | 2 | 50 |  |  |  | 8 | unless ($ns->namespace_uri($name)) { | 
| 226 | 2 |  |  |  |  | 6 | $ns->add_mapping( $name => $iri ); | 
| 227 |  |  |  |  |  |  | } | 
| 228 |  |  |  |  |  |  | } | 
| 229 |  |  |  |  |  |  | } | 
| 230 |  |  |  |  |  |  | elsif ($type == BASE or $type == SPARQLBASE) { | 
| 231 | 11 |  |  |  |  | 45 | $t	= $self->_get_token_type($l, IRI); | 
| 232 | 10 |  |  |  |  | 46 | my $r	= RDF::Trine::Node::Resource->new($t->value, $self->{baseURI}); | 
| 233 | 10 |  |  |  |  | 40 | my $iri	= $r->uri_value; | 
| 234 | 10 | 100 |  |  |  | 40 | if ($type == BASE) { | 
| 235 | 6 |  |  |  |  | 24 | $t	= $self->_get_token_type($l, DOT); | 
| 236 |  |  |  |  |  |  | # 			$t	= $self->_next_nonws($l); | 
| 237 |  |  |  |  |  |  | # 			if ($t and $t->type != DOT) { | 
| 238 |  |  |  |  |  |  | # 				$self->_unget_token($t); | 
| 239 |  |  |  |  |  |  | # 			} | 
| 240 |  |  |  |  |  |  | } | 
| 241 | 10 |  |  |  |  | 207 | $self->{baseURI}	= $iri; | 
| 242 |  |  |  |  |  |  | } | 
| 243 |  |  |  |  |  |  | else { | 
| 244 | 783 |  |  |  |  | 2859 | $self->_triple( $l, $t ); | 
| 245 | 709 |  |  |  |  | 2740 | $t	= $self->_get_token_type($l, DOT); | 
| 246 |  |  |  |  |  |  | } | 
| 247 |  |  |  |  |  |  | # 	} | 
| 248 |  |  |  |  |  |  | } | 
| 249 |  |  |  |  |  |  |  | 
| 250 |  |  |  |  |  |  | sub _triple { | 
| 251 | 783 |  |  | 783 |  | 1479 | my $self	= shift; | 
| 252 | 783 |  |  |  |  | 1443 | my $l		= shift; | 
| 253 | 783 |  |  |  |  | 1339 | my $t		= shift; | 
| 254 | 783 |  |  |  |  | 19649 | my $type	= $t->type; | 
| 255 |  |  |  |  |  |  | # subject | 
| 256 | 783 |  |  |  |  | 1671 | my $subj; | 
| 257 | 783 |  |  |  |  | 2012 | my $bnode_plist	= 0; | 
| 258 | 783 | 100 | 100 |  |  | 5995 | if ($type == LBRACKET) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 259 | 40 |  |  |  |  | 85 | $bnode_plist	= 1; | 
| 260 | 40 |  |  |  |  | 299 | $subj	= RDF::Trine::Node::Blank->new(); | 
| 261 | 40 |  |  |  |  | 128 | my $t	= $self->_next_nonws($l); | 
| 262 | 40 | 100 |  |  |  | 994 | if ($t->type != RBRACKET) { | 
| 263 | 11 |  |  |  |  | 52 | $self->_unget_token($t); | 
| 264 | 11 |  |  |  |  | 46 | $self->_predicateObjectList( $l, $subj ); | 
| 265 | 11 |  |  |  |  | 41 | $t	= $self->_get_token_type($l, RBRACKET); | 
| 266 |  |  |  |  |  |  | } | 
| 267 |  |  |  |  |  |  | } elsif ($type == LPAREN) { | 
| 268 | 4 |  |  |  |  | 17 | my $t	= $self->_next_nonws($l); | 
| 269 | 4 | 50 |  |  |  | 95 | if ($t->type == RPAREN) { | 
| 270 | 0 |  |  |  |  | 0 | $subj	= RDF::Trine::Node::Resource->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'); | 
| 271 |  |  |  |  |  |  | } else { | 
| 272 | 4 |  |  |  |  | 38 | $subj	= RDF::Trine::Node::Blank->new(); | 
| 273 | 4 |  |  |  |  | 22 | my @objects	= $self->_object($l, $t); | 
| 274 |  |  |  |  |  |  |  | 
| 275 | 4 |  |  |  |  | 9 | while (1) { | 
| 276 | 6 |  |  |  |  | 20 | my $t	= $self->_next_nonws($l); | 
| 277 | 6 | 100 |  |  |  | 269 | if ($t->type == RPAREN) { | 
| 278 | 4 |  |  |  |  | 106 | last; | 
| 279 |  |  |  |  |  |  | } else { | 
| 280 | 2 |  |  |  |  | 9 | push(@objects, $self->_object($l, $t)); | 
| 281 |  |  |  |  |  |  | } | 
| 282 |  |  |  |  |  |  | } | 
| 283 | 4 |  |  |  |  | 21 | $self->_assert_list($subj, @objects); | 
| 284 |  |  |  |  |  |  | } | 
| 285 |  |  |  |  |  |  | } elsif (not($type==IRI or $type==PREFIXNAME or $type==BNODE)) { | 
| 286 | 21 |  |  |  |  | 76 | $self->_throw_error("Expecting resource or bnode but got " . decrypt_constant($type), $t, $l); | 
| 287 |  |  |  |  |  |  | } else { | 
| 288 | 718 |  |  |  |  | 2321 | $subj	= $self->_token_to_node($t); | 
| 289 |  |  |  |  |  |  | } | 
| 290 |  |  |  |  |  |  | # 	warn "Subject: $subj\n";	# XXX | 
| 291 |  |  |  |  |  |  |  | 
| 292 | 758 | 100 |  |  |  | 2794 | if ($bnode_plist) { | 
| 293 |  |  |  |  |  |  | #predicateObjectList? | 
| 294 | 40 |  |  |  |  | 125 | $t	= $self->_next_nonws($l); | 
| 295 | 40 |  |  |  |  | 173 | $self->_unget_token($t); | 
| 296 | 40 | 100 |  |  |  | 998 | if ($t->type != DOT) { | 
| 297 | 34 |  |  |  |  | 141 | $self->_predicateObjectList($l, $subj); | 
| 298 |  |  |  |  |  |  | } | 
| 299 |  |  |  |  |  |  | } else { | 
| 300 |  |  |  |  |  |  | #predicateObjectList | 
| 301 | 718 |  |  |  |  | 2735 | $self->_predicateObjectList($l, $subj); | 
| 302 |  |  |  |  |  |  | } | 
| 303 |  |  |  |  |  |  | } | 
| 304 |  |  |  |  |  |  |  | 
| 305 |  |  |  |  |  |  | sub _assert_list { | 
| 306 | 24 |  |  | 24 |  | 63 | my $self	= shift; | 
| 307 | 24 |  |  |  |  | 50 | my $subj	= shift; | 
| 308 | 24 |  |  |  |  | 110 | my @objects	= @_; | 
| 309 | 24 |  |  |  |  | 54 | my $head	= $subj; | 
| 310 | 24 |  |  |  |  | 105 | while (@objects) { | 
| 311 | 330 |  |  |  |  | 663 | my $obj	= shift(@objects); | 
| 312 | 330 |  |  |  |  | 1907 | $self->_assert_triple($head, $rdf->first, $obj); | 
| 313 | 330 | 100 |  |  |  | 1435 | my $next	= scalar(@objects) ? RDF::Trine::Node::Blank->new() : $rdf->nil; | 
| 314 | 330 |  |  |  |  | 1849 | $self->_assert_triple($head, $rdf->rest, $next); | 
| 315 | 330 |  |  |  |  | 1746 | $head		= $next; | 
| 316 |  |  |  |  |  |  | } | 
| 317 |  |  |  |  |  |  | } | 
| 318 |  |  |  |  |  |  |  | 
| 319 |  |  |  |  |  |  | sub _predicateObjectList { | 
| 320 | 817 |  |  | 817 |  | 1679 | my $self	= shift; | 
| 321 | 817 |  |  |  |  | 1626 | my $l		= shift; | 
| 322 | 817 |  |  |  |  | 1554 | my $subj	= shift; | 
| 323 | 817 |  |  |  |  | 2198 | my $t		= $self->_next_nonws($l); | 
| 324 | 811 |  |  |  |  | 1603 | while (1) { | 
| 325 | 2208 |  |  |  |  | 53026 | my $type = $t->type; | 
| 326 | 2208 | 100 | 100 |  |  | 12004 | unless ($type==IRI or $type==PREFIXNAME or $type==A) { | 
|  |  |  | 100 |  |  |  |  | 
| 327 | 18 |  |  |  |  | 60 | $self->_throw_error("Expecting verb but got " . decrypt_constant($type), $t, $l); | 
| 328 |  |  |  |  |  |  | } | 
| 329 | 2190 |  |  |  |  | 6487 | my $pred	= $self->_token_to_node($t); | 
| 330 | 2187 |  |  |  |  | 6846 | $self->_objectList($l, $subj, $pred); | 
| 331 |  |  |  |  |  |  |  | 
| 332 | 2166 |  |  |  |  | 5892 | $t		= $self->_next_nonws($l); | 
| 333 | 2166 | 100 |  |  |  | 54272 | last unless ($t); | 
| 334 | 2163 | 100 |  |  |  | 52728 | if ($t->type == SEMICOLON) { | 
| 335 | 1690 |  |  |  |  | 2956 | my $sc	= $t; | 
| 336 | 1694 |  |  |  |  | 4087 | SEMICOLON_REPEAT: | 
| 337 |  |  |  |  |  |  | $t		= $self->_next_nonws($l); | 
| 338 | 1694 | 100 |  |  |  | 4134 | unless ($t) { | 
| 339 | 1 |  |  |  |  | 4 | $l->_throw_error("Expecting token after semicolon, but got EOF"); | 
| 340 |  |  |  |  |  |  | } | 
| 341 | 1693 | 100 |  |  |  | 39660 | goto SEMICOLON_REPEAT if ($t->type == SEMICOLON); | 
| 342 | 1689 | 100 | 100 |  |  | 39105 | if ($t->type == IRI or $t->type == PREFIXNAME or $t->type == A) { | 
|  |  |  | 66 |  |  |  |  | 
| 343 | 1397 |  |  |  |  | 36041 | next; | 
| 344 |  |  |  |  |  |  | } else { | 
| 345 | 292 |  |  |  |  | 1101 | $self->_unget_token($t); | 
| 346 | 292 |  |  |  |  | 7722 | return; | 
| 347 |  |  |  |  |  |  | } | 
| 348 |  |  |  |  |  |  | } else { | 
| 349 | 473 |  |  |  |  | 1472 | $self->_unget_token($t); | 
| 350 | 473 |  |  |  |  | 1885 | return; | 
| 351 |  |  |  |  |  |  | } | 
| 352 |  |  |  |  |  |  | } | 
| 353 |  |  |  |  |  |  | } | 
| 354 |  |  |  |  |  |  |  | 
| 355 |  |  |  |  |  |  | sub _objectList { | 
| 356 | 2187 |  |  | 2187 |  | 4218 | my $self	= shift; | 
| 357 | 2187 |  |  |  |  | 3661 | my $l		= shift; | 
| 358 | 2187 |  |  |  |  | 3341 | my $subj	= shift; | 
| 359 | 2187 |  |  |  |  | 3264 | my $pred	= shift; | 
| 360 |  |  |  |  |  |  | # 	warn "objectList: " . Dumper($subj, $pred);	# XXX | 
| 361 | 2187 |  |  |  |  | 3281 | while (1) { | 
| 362 | 2208 |  |  |  |  | 5456 | my $t		= $self->_next_nonws($l); | 
| 363 | 2197 | 100 |  |  |  | 5811 | last unless ($t); | 
| 364 | 2195 |  |  |  |  | 6625 | my $obj		= $self->_object($l, $t); | 
| 365 | 2188 |  |  |  |  | 7077 | $self->_assert_triple($subj, $pred, $obj); | 
| 366 |  |  |  |  |  |  |  | 
| 367 | 2188 |  |  |  |  | 6553 | $t	= $self->_next_nonws($l); | 
| 368 | 2185 | 100 | 100 |  |  | 62354 | if ($t and $t->type == COMMA) { | 
| 369 | 21 |  |  |  |  | 469 | next; | 
| 370 |  |  |  |  |  |  | } else { | 
| 371 | 2164 |  |  |  |  | 8121 | $self->_unget_token($t); | 
| 372 | 2164 |  |  |  |  | 4917 | return; | 
| 373 |  |  |  |  |  |  | } | 
| 374 |  |  |  |  |  |  | } | 
| 375 |  |  |  |  |  |  | } | 
| 376 |  |  |  |  |  |  |  | 
| 377 |  |  |  |  |  |  | sub _assert_triple { | 
| 378 | 2817 |  |  | 2817 |  | 4682 | my $self	= shift; | 
| 379 | 2817 |  |  |  |  | 4827 | my $subj	= shift; | 
| 380 | 2817 |  |  |  |  | 4305 | my $pred	= shift; | 
| 381 | 2817 |  |  |  |  | 4176 | my $obj		= shift; | 
| 382 | 2817 | 100 | 66 |  |  | 24996 | if ($self->{canonicalize} and blessed($obj) and $obj->isa('RDF::Trine::Node::Literal')) { | 
|  |  |  | 100 |  |  |  |  | 
| 383 | 588 |  |  |  |  | 2366 | $obj	= $obj->canonicalize; | 
| 384 |  |  |  |  |  |  | } | 
| 385 |  |  |  |  |  |  |  | 
| 386 | 2817 |  |  |  |  | 13968 | my $t		= RDF::Trine::Statement->new($subj, $pred, $obj); | 
| 387 | 2817 | 100 |  |  |  | 8344 | if ($self->{handle_triple}) { | 
| 388 | 2613 |  |  |  |  | 8965 | $self->{handle_triple}->( $t ); | 
| 389 |  |  |  |  |  |  | } | 
| 390 |  |  |  |  |  |  | } | 
| 391 |  |  |  |  |  |  |  | 
| 392 |  |  |  |  |  |  | sub _object { | 
| 393 | 2527 |  |  | 2527 |  | 4356 | my $self	= shift; | 
| 394 | 2527 |  |  |  |  | 4289 | my $l		= shift; | 
| 395 | 2527 |  |  |  |  | 4256 | my $t		= shift; | 
| 396 | 2527 |  |  |  |  | 60467 | my $type	= $t->type; | 
| 397 | 2527 |  |  |  |  | 4468 | my $tcopy	= $t; | 
| 398 | 2527 |  |  |  |  | 3806 | my $obj; | 
| 399 | 2527 | 100 | 100 |  |  | 19678 | if ($type==LBRACKET) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
| 400 | 36 |  |  |  |  | 186 | $obj	= RDF::Trine::Node::Blank->new(); | 
| 401 | 36 |  |  |  |  | 119 | my $t	= $self->_next_nonws($l); | 
| 402 | 36 | 50 |  |  |  | 124 | unless ($t) { | 
| 403 | 0 |  |  |  |  | 0 | $self->_throw_error("Expecting object but got only opening bracket", $tcopy, $l); | 
| 404 |  |  |  |  |  |  | } | 
| 405 | 36 | 100 |  |  |  | 880 | if ($t->type != RBRACKET) { | 
| 406 | 28 |  |  |  |  | 105 | $self->_unget_token($t); | 
| 407 | 28 |  |  |  |  | 127 | $self->_predicateObjectList( $l, $obj ); | 
| 408 | 28 |  |  |  |  | 88 | $t	= $self->_get_token_type($l, RBRACKET); | 
| 409 |  |  |  |  |  |  | } | 
| 410 |  |  |  |  |  |  | } elsif ($type == LPAREN) { | 
| 411 | 27 |  |  |  |  | 93 | my $t	= $self->_next_nonws($l); | 
| 412 | 27 | 50 |  |  |  | 90 | unless ($t) { | 
| 413 | 0 |  |  |  |  | 0 | $self->_throw_error("Expecting object but got only opening paren", $tcopy, $l); | 
| 414 |  |  |  |  |  |  | } | 
| 415 | 27 | 100 |  |  |  | 668 | if ($t->type == RPAREN) { | 
| 416 | 6 |  |  |  |  | 30 | $obj	= RDF::Trine::Node::Resource->new('http://www.w3.org/1999/02/22-rdf-syntax-ns#nil'); | 
| 417 |  |  |  |  |  |  | } else { | 
| 418 | 21 |  |  |  |  | 166 | $obj	= RDF::Trine::Node::Blank->new(); | 
| 419 | 21 |  |  |  |  | 103 | my @objects	= $self->_object($l, $t); | 
| 420 |  |  |  |  |  |  |  | 
| 421 | 21 |  |  |  |  | 50 | while (1) { | 
| 422 | 325 |  |  |  |  | 1023 | my $t	= $self->_next_nonws($l); | 
| 423 | 325 | 100 |  |  |  | 8158 | if ($t->type == RPAREN) { | 
| 424 | 20 |  |  |  |  | 554 | last; | 
| 425 |  |  |  |  |  |  | } else { | 
| 426 | 305 |  |  |  |  | 979 | push(@objects, $self->_object($l, $t)); | 
| 427 |  |  |  |  |  |  | } | 
| 428 |  |  |  |  |  |  | } | 
| 429 | 20 |  |  |  |  | 114 | $self->_assert_list($obj, @objects); | 
| 430 |  |  |  |  |  |  | } | 
| 431 |  |  |  |  |  |  | } elsif (not($type==IRI or $type==PREFIXNAME or $type==STRING1D or $type==STRING3D or $type==STRING1S or $type==STRING3S or $type==BNODE or $type==INTEGER or $type==DECIMAL or $type==DOUBLE or $type==BOOLEAN)) { | 
| 432 | 2 |  |  |  |  | 13 | $self->_throw_error("Expecting object but got " . decrypt_constant($type), $t, $l); | 
| 433 |  |  |  |  |  |  | } else { | 
| 434 | 2462 |  |  |  |  | 6895 | $obj		= $self->_term($l, $t); | 
| 435 |  |  |  |  |  |  | } | 
| 436 | 2519 |  |  |  |  | 14319 | return $obj; | 
| 437 |  |  |  |  |  |  | } | 
| 438 |  |  |  |  |  |  |  | 
| 439 |  |  |  |  |  |  | sub _term { | 
| 440 | 2486 |  |  | 2486 |  | 4448 | my $self	= shift; | 
| 441 | 2486 |  |  |  |  | 3682 | my $l		= shift; | 
| 442 | 2486 |  |  |  |  | 3851 | my $t		= shift; | 
| 443 | 2486 |  |  |  |  | 3784 | my $tcopy	= $t; | 
| 444 | 2486 |  |  |  |  | 3601 | my $obj; | 
| 445 | 2486 |  |  |  |  | 61269 | my $type	= $t->type; | 
| 446 | 2486 | 100 | 100 |  |  | 16790 | if ($type==STRING1D or $type==STRING3D or $type==STRING1S or $type==STRING3S) { | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 100 |  |  |  |  | 
| 447 | 781 |  |  |  |  | 2626 | my $value	= $t->value; | 
| 448 | 781 |  |  |  |  | 2218 | my $t		= $self->_next_nonws($l); | 
| 449 | 778 |  |  |  |  | 1872 | my $dt; | 
| 450 |  |  |  |  |  |  | my $lang; | 
| 451 | 778 | 50 |  |  |  | 2390 | if ($t) { | 
| 452 | 778 | 100 |  |  |  | 18683 | if ($t->type == HATHAT) { | 
|  |  | 100 |  |  |  |  |  | 
| 453 | 36 |  |  |  |  | 133 | my $t		= $self->_next_nonws($l); | 
| 454 | 36 | 50 | 66 |  |  | 862 | if ($t->type == IRI or $t->type == PREFIXNAME) { | 
| 455 | 36 |  |  |  |  | 138 | $dt	= $self->_token_to_node($t); | 
| 456 |  |  |  |  |  |  | } | 
| 457 |  |  |  |  |  |  | } elsif ($t->type == LANG) { | 
| 458 | 15 |  |  |  |  | 55 | $lang	= $t->value; | 
| 459 |  |  |  |  |  |  | } else { | 
| 460 | 727 |  |  |  |  | 2202 | $self->_unget_token($t); | 
| 461 |  |  |  |  |  |  | } | 
| 462 |  |  |  |  |  |  | } | 
| 463 | 778 |  |  |  |  | 4477 | $obj	= RDF::Trine::Node::Literal->new($value, $lang, $dt); | 
| 464 |  |  |  |  |  |  | } else { | 
| 465 | 1705 |  |  |  |  | 4785 | $obj	= $self->_token_to_node($t, $type); | 
| 466 |  |  |  |  |  |  | } | 
| 467 | 2482 |  |  |  |  | 5983 | return $obj; | 
| 468 |  |  |  |  |  |  | } | 
| 469 |  |  |  |  |  |  |  | 
| 470 |  |  |  |  |  |  | sub _token_to_node { | 
| 471 | 4682 |  |  | 4682 |  | 7932 | my $self	= shift; | 
| 472 | 4682 |  |  |  |  | 7884 | my $t		= shift; | 
| 473 | 4682 |  | 66 |  |  | 79405 | my $type	= shift || $t->type; | 
| 474 | 4682 | 100 |  |  |  | 23092 | if ($type eq A) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 475 | 55 |  |  |  |  | 487 | return $rdf->type; | 
| 476 |  |  |  |  |  |  | } | 
| 477 |  |  |  |  |  |  | elsif ($type eq IRI) { | 
| 478 | 1599 |  |  |  |  | 5193 | return RDF::Trine::Node::Resource->new($t->value, $self->{baseURI}); | 
| 479 |  |  |  |  |  |  | } | 
| 480 |  |  |  |  |  |  | elsif ($type eq INTEGER) { | 
| 481 | 59 |  |  |  |  | 215 | return RDF::Trine::Node::Literal->new($t->value, undef, $xsd->integer); | 
| 482 |  |  |  |  |  |  | } | 
| 483 |  |  |  |  |  |  | elsif ($type eq DECIMAL) { | 
| 484 | 11 |  |  |  |  | 61 | return RDF::Trine::Node::Literal->new($t->value, undef, $xsd->decimal); | 
| 485 |  |  |  |  |  |  | } | 
| 486 |  |  |  |  |  |  | elsif ($type eq DOUBLE) { | 
| 487 | 9 |  |  |  |  | 32 | return RDF::Trine::Node::Literal->new($t->value, undef, $xsd->double); | 
| 488 |  |  |  |  |  |  | } | 
| 489 |  |  |  |  |  |  | elsif ($type eq BOOLEAN) { | 
| 490 | 8 |  |  |  |  | 41 | return RDF::Trine::Node::Literal->new($t->value, undef, $xsd->boolean); | 
| 491 |  |  |  |  |  |  | } | 
| 492 |  |  |  |  |  |  | elsif ($type eq PREFIXNAME) { | 
| 493 | 2860 |  |  |  |  | 4499 | my ($ns, $local)	= @{ $t->args }; | 
|  | 2860 |  |  |  |  | 70081 |  | 
| 494 | 2860 |  |  |  |  | 10836 | $ns		=~ s/:$//; | 
| 495 | 2860 |  |  |  |  | 12358 | my $prefix			= $self->{map}->namespace_uri($ns); | 
| 496 | 2860 | 100 |  |  |  | 11813 | unless (blessed($prefix)) { | 
| 497 | 8 |  |  |  |  | 35 | $self->_throw_error("Use of undeclared prefix '$ns'", $t); | 
| 498 |  |  |  |  |  |  | } | 
| 499 | 2852 |  |  |  |  | 10872 | my $iri				= $prefix->uri($local); | 
| 500 | 2852 |  |  |  |  | 7000 | return $iri; | 
| 501 |  |  |  |  |  |  | } | 
| 502 |  |  |  |  |  |  | elsif ($type eq BNODE) { | 
| 503 | 81 |  |  |  |  | 321 | return RDF::Trine::Node::Blank->new($t->value); | 
| 504 |  |  |  |  |  |  | } | 
| 505 |  |  |  |  |  |  | elsif ($type eq STRING1D) { | 
| 506 | 0 |  |  |  |  | 0 | return RDF::Trine::Node::Literal->new($t->value); | 
| 507 |  |  |  |  |  |  | } | 
| 508 |  |  |  |  |  |  | elsif ($type eq STRING1S) { | 
| 509 | 0 |  |  |  |  | 0 | return RDF::Trine::Node::Literal->new($t->value); | 
| 510 |  |  |  |  |  |  | } | 
| 511 |  |  |  |  |  |  | else { | 
| 512 | 0 |  |  |  |  | 0 | $self->_throw_error("Converting $type to node not implemented", $t); | 
| 513 |  |  |  |  |  |  | } | 
| 514 |  |  |  |  |  |  | } | 
| 515 |  |  |  |  |  |  |  | 
| 516 |  |  |  |  |  |  | sub _throw_error { | 
| 517 | 61 |  |  | 61 |  | 115 | my $self	= shift; | 
| 518 | 61 |  |  |  |  | 95 | my $message	= shift; | 
| 519 | 61 |  |  |  |  | 96 | my $t		= shift; | 
| 520 | 61 |  |  |  |  | 83 | my $l		= shift; | 
| 521 | 61 |  |  |  |  | 1607 | my $line	= $t->start_line; | 
| 522 | 61 |  |  |  |  | 1580 | my $col		= $t->start_column; | 
| 523 |  |  |  |  |  |  | # 	Carp::cluck "$message at $line:$col"; | 
| 524 | 61 |  |  |  |  | 186 | my $text	= "$message at $line:$col"; | 
| 525 | 61 | 100 |  |  |  | 176 | if (defined($t->value)) { | 
| 526 | 30 |  |  |  |  | 81 | $text	.= " (near '" . $t->value . "')"; | 
| 527 |  |  |  |  |  |  | } | 
| 528 |  |  |  |  |  |  | RDF::Trine::Error::ParserError::Tokenized->throw( | 
| 529 | 61 |  |  |  |  | 601 | -text => $text, | 
| 530 |  |  |  |  |  |  | -object => $t, | 
| 531 |  |  |  |  |  |  | ); | 
| 532 |  |  |  |  |  |  | } | 
| 533 |  |  |  |  |  |  |  | 
| 534 |  |  |  |  |  |  | 1; | 
| 535 |  |  |  |  |  |  |  | 
| 536 |  |  |  |  |  |  | __END__ | 
| 537 |  |  |  |  |  |  |  | 
| 538 |  |  |  |  |  |  | =back | 
| 539 |  |  |  |  |  |  |  | 
| 540 |  |  |  |  |  |  | =head1 BUGS | 
| 541 |  |  |  |  |  |  |  | 
| 542 |  |  |  |  |  |  | Please report any bugs or feature requests to through the GitHub web interface | 
| 543 |  |  |  |  |  |  | at L<https://github.com/kasei/perlrdf/issues>. | 
| 544 |  |  |  |  |  |  |  | 
| 545 |  |  |  |  |  |  | =head1 AUTHOR | 
| 546 |  |  |  |  |  |  |  | 
| 547 |  |  |  |  |  |  | Gregory Todd Williams  C<< <gwilliams@cpan.org> >> | 
| 548 |  |  |  |  |  |  |  | 
| 549 |  |  |  |  |  |  | =head1 COPYRIGHT | 
| 550 |  |  |  |  |  |  |  | 
| 551 |  |  |  |  |  |  | Copyright (c) 2006-2012 Gregory Todd Williams. This | 
| 552 |  |  |  |  |  |  | program is free software; you can redistribute it and/or modify it under | 
| 553 |  |  |  |  |  |  | the same terms as Perl itself. | 
| 554 |  |  |  |  |  |  |  | 
| 555 |  |  |  |  |  |  | =cut |