File Coverage

blib/lib/RDF/Trine/Node/Literal.pm
Criterion Covered Total %
statement 226 312 72.4
branch 107 204 52.4
condition 23 42 54.7
subroutine 35 37 94.5
pod 18 18 100.0
total 409 613 66.7


line stmt bran cond sub pod time code
1             # RDF::Trine::Node::Literal
2             # -----------------------------------------------------------------------------
3              
4             =head1 NAME
5              
6             RDF::Trine::Node::Literal - RDF Node class for literals
7              
8             =head1 VERSION
9              
10             This document describes RDF::Trine::Node::Literal version 1.018
11              
12             =cut
13              
14             package RDF::Trine::Node::Literal;
15              
16 68     68   382 use strict;
  68         133  
  68         1554  
17 68     68   301 use warnings;
  68         122  
  68         1538  
18 68     68   291 no warnings 'redefine';
  68         136  
  68         1726  
19 68     68   315 use base qw(RDF::Trine::Node);
  68         129  
  68         3939  
20              
21 68     68   21185 use RDF::Trine::Error;
  68         197  
  68         536  
22 68     68   3747 use Data::Dumper;
  68         147  
  68         2912  
23 68     68   398 use Scalar::Util qw(blessed looks_like_number);
  68         136  
  68         3121  
24 68     68   365 use Carp qw(carp croak confess);
  68         141  
  68         7467  
25              
26             ######################################################################
27              
28             our ($VERSION, $USE_XMLLITERALS, $USE_FORMULAE);
29             BEGIN {
30 68     68   232 $VERSION = '1.018';
31 68     68   4696 eval "use RDF::Trine::Node::Literal::XML;"; ## no critic (ProhibitStringyEval)
  68         10838  
  0         0  
  0         0  
32 68 50       866 $USE_XMLLITERALS = (RDF::Trine::Node::Literal::XML->can('new')) ? 1 : 0;
33 68     68   3442 eval "use RDF::Trine::Node::Formula;"; ## no critic (ProhibitStringyEval)
  68         10448  
  0         0  
  0         0  
34 68 50       3369 $USE_FORMULAE = (RDF::Trine::Node::Formula->can('new')) ? 1 : 0;
35             }
36              
37             ######################################################################
38              
39 4150     4150   16400 use overload '""' => sub { $_[0]->sse },
40 68     68   376 ;
  68         132  
  68         591  
41              
42             =head1 METHODS
43              
44             Beyond the methods documented below, this class inherits methods from the
45             L<RDF::Trine::Node> class.
46              
47             =over 4
48              
49             =cut
50              
51             =item C<new ( $string, $lang, $datatype, $canonical_flag )>
52              
53             Returns a new Literal structure.
54              
55             =cut
56              
57             sub new {
58 2360     2360 1 8270 my $class = shift;
59 2360         3891 my $literal = shift;
60 2360         4452 my $lang = shift;
61 2360         3970 my $dt = shift;
62 2360         4144 my $canon = shift;
63            
64 2360 50       6018 unless (defined($literal)) {
65 0         0 throw RDF::Trine::Error::MethodInvocationError -text => "Literal constructor called with an undefined value";
66             }
67            
68 2360 100 66     9447 if (blessed($dt) and $dt->isa('RDF::Trine::Node::Resource')) {
69 167         572 $dt = $dt->uri_value;
70             }
71            
72 2360 100 100     7388 if ($dt and $canon) {
73 25         62 $literal = $class->canonicalize_literal_value( $literal, $dt );
74             }
75            
76 2360 50 33     12038 if ($USE_XMLLITERALS and defined($dt) and $dt eq 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral') {
    50 33        
      33        
      33        
77 0         0 return RDF::Trine::Node::Literal::XML->new( $literal, $lang, $dt );
78             } elsif ($USE_FORMULAE and defined($dt) and $dt eq RDF::Trine::Node::Formula->literal_datatype) {
79 0         0 return RDF::Trine::Node::Formula->new( $literal );
80             } else {
81 2360         6779 return $class->_new( $literal, $lang, $dt );
82             }
83             }
84              
85             sub _new {
86 2360     2360   3829 my $class = shift;
87 2360         3769 my $literal = shift;
88 2360         3665 my $lang = shift;
89 2360         3581 my $dt = shift;
90 2360         3822 my $self;
91              
92 2360 100 100     6742 if ($lang and $dt) {
93 1         17 throw RDF::Trine::Error::MethodInvocationError ( -text => "Literal values cannot have both language and datatype" );
94             }
95            
96 2359 100       6557 if ($lang) {
    100          
97 89         181 my $oldlang = $lang;
98             # http://tools.ietf.org/html/bcp47#section-2.1.1
99             # All subtags use lowercase letters
100 89         211 $lang = lc($lang);
101              
102             # with 2 exceptions: subtags that neither appear at the start of the tag nor occur after singletons
103             # i.e. there's a subtag of length at least 2 preceding the exception; and a following subtag or end-of-tag
104              
105             # 1. two-letter subtags are all uppercase
106 89         347 $lang =~ s{(?<=\w\w-)(\w\w)(?=($|-))}{\U$1}g;
107              
108             # 2. four-letter subtags are titlecase
109 89         193 $lang =~ s{(?<=\w\w-)(\w\w\w\w)(?=($|-))}{\u\L$1}g;
110 89         274 $self = [ $literal, $lang, undef ];
111             } elsif ($dt) {
112 372 50       1212 if (blessed($dt)) {
113 0         0 $dt = $dt->uri_value;
114             }
115 372         1096 $self = [ $literal, undef, $dt ];
116             } else {
117 1898         4431 $self = [ $literal ];
118             }
119 2359         10703 return bless($self, $class);
120             }
121              
122              
123             =item C<< literal_value >>
124              
125             Returns the string value of the literal.
126              
127             =cut
128              
129             sub literal_value {
130 11862     11862 1 78327 my $self = shift;
131 11862 100       26376 if (@_) {
132 1         3 $self->[0] = shift;
133             }
134 11862         30525 return $self->[0];
135             }
136              
137             =item C<< literal_value_language >>
138              
139             Returns the language tag of the ltieral.
140              
141             =cut
142              
143             sub literal_value_language {
144 11363     11363 1 16801 my $self = shift;
145 11363         30930 return $self->[1];
146             }
147              
148             =item C<< literal_datatype >>
149              
150             Returns the datatype of the literal.
151              
152             =cut
153              
154             sub literal_datatype {
155 10876     10876 1 16367 my $self = shift;
156 10876         25907 return $self->[2];
157             }
158              
159             =item C<< value >>
160              
161             Returns the literal value.
162              
163             =cut
164              
165             sub value {
166 590     590 1 936 my $self = shift;
167 590         1490 return $self->literal_value;
168             }
169              
170             =item C<< sse >>
171              
172             Returns the SSE string for this literal.
173              
174             =cut
175              
176             sub sse {
177 6293     6293 1 10074 my $self = shift;
178 6293         13391 my $literal = $self->literal_value;
179 6293         19128 my $escaped = $self->_unicode_escape( $literal );
180 6293         11209 $literal = $escaped;
181 6293 100       12674 if (defined(my $lang = $self->literal_value_language)) {
    100          
182 342         1354 return qq("${literal}"\@${lang});
183             } elsif (defined(my $dt = $self->literal_datatype)) {
184 1553         7916 return qq("${literal}"^^<${dt}>);
185             } else {
186 4398         17768 return qq("${literal}");
187             }
188             }
189              
190             =item C<< as_string >>
191              
192             Returns a string representation of the node.
193              
194             =cut
195              
196             sub as_string {
197 3370     3370 1 8176 my $self = shift;
198 3370         7060 my $string = '"' . $self->literal_value . '"';
199 3370 100       7902 if (defined(my $dt = $self->literal_datatype)) {
    100          
200 789         2113 $string .= '^^<' . $dt . '>';
201             } elsif (defined(my $lang = $self->literal_value_language)) {
202 200         424 $string .= '@' . $lang;
203             }
204 3370         10891 return $string;
205             }
206              
207             =item C<< as_ntriples >>
208              
209             Returns the node in a string form suitable for NTriples serialization.
210              
211             =cut
212              
213             sub as_ntriples {
214 649     649 1 1103 my $self = shift;
215 649         1605 my $literal = $self->literal_value;
216 649         2319 my $escaped = $self->_unicode_escape( $literal );
217 649         1195 $literal = $escaped;
218 649 100       1398 if (defined(my $lang = $self->literal_value_language)) {
    100          
219 22         141 return qq("${literal}"\@${lang});
220             } elsif (defined(my $dt = $self->literal_datatype)) {
221 162         1143 return qq("${literal}"^^<${dt}>);
222             } else {
223 465         2731 return qq("${literal}");
224             }
225             }
226              
227             =item C<< type >>
228              
229             Returns the type string of this node.
230              
231             =cut
232              
233             sub type {
234 621     621 1 1235 return 'LITERAL';
235             }
236              
237             =item C<< has_language >>
238              
239             Returns true if this literal is language-tagged, false otherwise.
240              
241             =cut
242              
243             sub has_language {
244 568     568 1 913 my $self = shift;
245 568 100       1202 return defined($self->literal_value_language) ? 1 : 0;
246             }
247              
248             =item C<< has_datatype >>
249              
250             Returns true if this literal is datatyped, false otherwise.
251              
252             =cut
253              
254             sub has_datatype {
255 108     108 1 227 my $self = shift;
256 108 100       280 return defined($self->literal_datatype) ? 1 : 0;
257             }
258              
259             =item C<< equal ( $node ) >>
260              
261             Returns true if the two nodes are equal, false otherwise.
262              
263             =cut
264              
265             sub equal {
266 17     17 1 44 my $self = shift;
267 17         30 my $node = shift;
268 17 100 100     153 return 0 unless (blessed($node) and $node->isa('RDF::Trine::Node::Literal'));
269 11 100       34 return 0 unless ($self->literal_value eq $node->literal_value);
270 10 100 66     24 if ($self->literal_datatype or $node->literal_datatype) {
271 68     68   54684 no warnings 'uninitialized';
  68         188  
  68         3639  
272 4 100       11 return 0 unless ($self->literal_datatype eq $node->literal_datatype);
273             }
274 9 100 66     24 if ($self->literal_value_language or $node->literal_value_language) {
275 68     68   389 no warnings 'uninitialized';
  68         173  
  68         43591  
276 3 100       9 return 0 unless ($self->literal_value_language eq $node->literal_value_language);
277             }
278 8         34 return 1;
279             }
280              
281             # called to compare two nodes of the same type
282             sub _compare {
283 144     144   211 my $a = shift;
284 144         222 my $b = shift;
285 144 50       283 if ($a->literal_value ne $b->literal_value) {
286 144         284 return ($a->literal_value cmp $b->literal_value);
287             }
288            
289             # the nodes have the same lexical value
290 0 0 0     0 if ($a->has_language and $b->has_language) {
291 0         0 return ($a->literal_value_language cmp $b->literal_value_language);
292             }
293            
294 0 0 0     0 if ($a->has_datatype and $b->has_datatype) {
    0          
    0          
295 0         0 return ($a->literal_datatype cmp $b->literal_datatype);
296             } elsif ($a->has_datatype) {
297 0         0 return 1;
298             } elsif ($b->has_datatype) {
299 0         0 return -1;
300             }
301            
302 0         0 return 0;
303             }
304              
305             =item C<< canonicalize >>
306              
307             Returns a new literal node object whose value is in canonical form (where applicable).
308              
309             =cut
310              
311             sub canonicalize {
312 588     588 1 1080 my $self = shift;
313 588         1257 my $class = ref($self);
314 588         2080 my $dt = $self->literal_datatype;
315 588         1734 my $lang = $self->literal_value_language;
316 588         1357 my $value = $self->value;
317 588 100       1611 if (defined $dt) {
318 5         13 $value = RDF::Trine::Node::Literal->canonicalize_literal_value( $value, $dt, 1 );
319             }
320 588         1405 return $class->new($value, $lang, $dt);
321             }
322              
323             =item C<< canonicalize_literal_value ( $string, $datatype, $warn ) >>
324              
325             If C<< $datatype >> is a recognized datatype, returns the canonical lexical
326             representation of the value C<< $string >>. Otherwise returns C<< $string >>.
327              
328             Currently, xsd:integer, xsd:decimal, and xsd:boolean are canonicalized.
329             Additionally, invalid lexical forms for xsd:float, xsd:double, and xsd:dateTime
330             will trigger a warning.
331              
332             =cut
333              
334             sub canonicalize_literal_value {
335 40     40 1 65 my $self = shift;
336 40         68 my $value = shift;
337 40         64 my $dt = shift;
338 40         66 my $warn = shift;
339            
340 40 100       172 if ($dt eq 'http://www.w3.org/2001/XMLSchema#integer') {
    100          
    100          
    100          
    50          
    0          
341 9 50       51 if ($value =~ m/^([-+])?(\d+)$/) {
342 9   100     44 my $sign = $1 || '';
343 9         21 my $num = $2;
344 9 100       38 $sign = '' if ($sign eq '+');
345 9         39 $num =~ s/^0+(\d)/$1/;
346 9         53 return "${sign}${num}";
347             } else {
348 0 0       0 warn "Bad lexical form for xsd:integer: '$value'" if ($warn);
349             }
350             } elsif ($dt eq 'http://www.w3.org/2001/XMLSchema#decimal') {
351 5 50       37 if ($value =~ m/^([-+])?((\d+)([.]\d*)?)$/) {
    0          
352 5   100     29 my $sign = $1 || '';
353 5         17 my $num = $2;
354 5         12 my $int = $3;
355 5         16 my $frac = $4;
356 5 100       20 $sign = '' if ($sign eq '+');
357 5         20 $num =~ s/^0+(.)/$1/;
358 5         39 $num =~ s/[.](\d)0+$/.$1/;
359 5 100       26 if ($num =~ /^[.]/) {
360 1         3 $num = "0$num";
361             }
362 5 50       28 if ($num !~ /[.]/) {
363 0         0 $num = "${num}.0";
364             }
365 5         29 return "${sign}${num}";
366             } elsif ($value =~ m/^([-+])?([.]\d+)$/) {
367 0   0     0 my $sign = $1 || '';
368 0         0 my $num = $2;
369 0 0       0 $sign = '' if ($sign eq '+');
370 0         0 $num =~ s/^0+(.)/$1/;
371 0         0 return "${sign}${num}";
372             } else {
373 0 0       0 warn "Bad lexical form for xsd:deciaml: '$value'" if ($warn);
374 0         0 $value = sprintf('%f', $value);
375             }
376             } elsif ($dt eq 'http://www.w3.org/2001/XMLSchema#float') {
377 8 50       37 if ($value =~ m/^(?:([-+])?(?:(\d+(?:\.\d*)?|\.\d+)([Ee][-+]?\d+)?|(INF)))|(NaN)$/) {
378 8         20 my $sign = $1;
379 8         16 my $inf = $4;
380 8         13 my $nan = $5;
381 68     68   489 no warnings 'uninitialized';
  68         138  
  68         21539  
382 8 100       20 $sign = '' if ($sign eq '+');
383 8 100       42 return "${sign}$inf" if ($inf);
384 8 100       15 return $nan if ($nan);
385              
386 7         37 $value = sprintf('%E', $value);
387 7         20 $value =~ m/^(?:([-+])?(?:(\d+(?:\.\d*)?|\.\d+)([Ee][-+]?\d+)?|(INF)))|(NaN)$/;
388 7         11 $sign = $1;
389 7         6 $inf = $4;
390 7         10 $nan = $5;
391 7         7 my $num = $2;
392 7         11 my $exp = $3;
393 7         31 $num =~ s/[.](\d+?)0+/.$1/;
394 7         11 $exp =~ tr/e/E/;
395 7         15 $exp =~ s/E[+]/E/;
396 7         21 $exp =~ s/E(-?)0+([1-9])$/E$1$2/;
397 7         12 $exp =~ s/E(-?)0+$/E${1}0/;
398 7         19 return "${sign}${num}${exp}";
399             } else {
400 0 0       0 warn "Bad lexical form for xsd:float: '$value'" if ($warn);
401 0         0 $value = sprintf('%E', $value);
402 0         0 $value =~ s/E[+]/E/;
403 0         0 $value =~ s/E0+(\d)/E$1/;
404 0         0 $value =~ s/(\d)0+E/$1E/;
405             }
406             } elsif ($dt eq 'http://www.w3.org/2001/XMLSchema#double') {
407 8 50       64 if ($value =~ m/^(?:([-+])?(?:(\d+(?:\.\d*)?|\.\d+)([Ee][-+]?\d+)?|(INF)))|(NaN)$/) {
408 8         19 my $sign = $1;
409 8         17 my $inf = $4;
410 8         13 my $nan = $5;
411 68     68   458 no warnings 'uninitialized';
  68         141  
  68         114798  
412 8 100       22 $sign = '' if ($sign eq '+');
413 8 100       50 return "${sign}$inf" if ($inf);
414 8 100       15 return $nan if ($nan);
415              
416 7         42 $value = sprintf('%E', $value);
417 7         18 $value =~ m/^(?:([-+])?(?:(\d+(?:\.\d*)?|\.\d+)([Ee][-+]?\d+)?|(INF)))|(NaN)$/;
418 7         10 $sign = $1;
419 7         9 $inf = $4;
420 7         7 $nan = $5;
421 7         10 my $num = $2;
422 7         8 my $exp = $3;
423 7         33 $num =~ s/[.](\d+?)0+/.$1/;
424 7         12 $exp =~ tr/e/E/;
425 7         11 $exp =~ s/E[+]/E/;
426 7         22 $exp =~ s/E(-?)0+([1-9])$/E$1$2/;
427 7         12 $exp =~ s/E(-?)0+$/E${1}0/;
428 7         17 return "${sign}${num}${exp}";
429             } else {
430 0 0       0 warn "Bad lexical form for xsd:double: '$value'" if ($warn);
431 0         0 $value = sprintf('%E', $value);
432 0         0 $value =~ s/E[+]/E/;
433 0         0 $value =~ s/E0+(\d)/E$1/;
434 0         0 $value =~ s/(\d)0+E/$1E/;
435             }
436             } elsif ($dt eq 'http://www.w3.org/2001/XMLSchema#boolean') {
437 10 50       53 if ($value =~ m/^(true|false|0|1)$/) {
438 10 100       60 $value = 'true' if ($value eq '1');
439 10 100       31 $value = 'false' if ($value eq '0');
440 10         29 return $value;
441             } else {
442 0 0       0 warn "Bad lexical form for xsd:boolean: '$value'" if ($warn);
443             }
444             } elsif ($dt eq 'http://www.w3.org/2001/XMLSchema#dateTime') {
445 0 0       0 if ($value =~ m/^-?([1-9]\d{3,}|0\d{3})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T(([01]\d|2[0-3]):[0-5]\d:[0-5]\d(\.\d+)?|(24:00:00(\.0+)?))(Z|(\+|-)((0\d|1[0-3]):[0-5]\d|14:00))?$/) {
446             # XXX need to canonicalize the dateTime
447 0         0 return $value;
448             } else {
449 0 0       0 warn "Bad lexical form for xsd:boolean: '$value'" if ($warn);
450             }
451             }
452 18         0 return $value;
453             }
454              
455             =item C<< is_canonical_lexical_form >>
456              
457             =cut
458              
459             sub is_canonical_lexical_form {
460 24     24 1 55 my $self = shift;
461 24         65 my $value = $self->literal_value;
462 24         57 my $dt = $self->literal_datatype;
463            
464 24 50       237 unless ($dt =~ qr<^http://www.w3.org/2001/XMLSchema#(integer|decimal|float|double|boolean|dateTime|non(Positive|Negative)Integer|(positive|negative)Integer|long|int|short|byte|unsigned(Long|Int|Short|Byte))>) {
465 0         0 return '0E0'; # zero but true (it's probably ok, but we don't recognize the datatype)
466             }
467            
468 24 100       161 if ($dt =~ m<http://www.w3.org/2001/XMLSchema#(integer|non(Positive|Negative)Integer|(positive|negative)Integer|long|int|short|byte|unsigned(Long|Int|Short|Byte))>) {
    100          
    50          
    50          
    0          
    0          
469 18 100       94 if ($value =~ m/^([-+])?(\d+)$/) {
470 17         92 return 1;
471             } else {
472 1         6 return 0;
473             }
474             } elsif ($dt eq 'http://www.w3.org/2001/XMLSchema#decimal') {
475 3 100       17 if ($value =~ m/^([-+])?((\d+)[.]\d+)$/) {
    100          
476 1         5 return 1;
477             } elsif ($value =~ m/^([-+])?([.]\d+)$/) {
478 1         6 return 1;
479             } else {
480 1         5 return 0;
481             }
482             } elsif ($dt eq 'http://www.w3.org/2001/XMLSchema#float') {
483 0 0       0 if ($value =~ m/^[-+]?(\d+\.\d*|\.\d+)([Ee][-+]?\d+)?|[-+]?INF|NaN$/) {
    0          
484 0         0 return 1;
485             } elsif ($value =~ m/^[-+]?(\d+(\.\d*)?|\.\d+)([Ee][-+]?\d+)|[-+]?INF|NaN$/) {
486 0         0 return 1;
487             } else {
488 0         0 return 0;
489             }
490             } elsif ($dt eq 'http://www.w3.org/2001/XMLSchema#double') {
491 3 100       25 if ($value =~ m/^[-+]?((\d+(\.\d*))|(\.\d+))([Ee][-+]?\d+)?|[-+]?INF|NaN$/) {
    100          
492 1         9 return 1;
493             } elsif ($value =~ m/^[-+]?((\d+(\.\d*)?)|(\.\d+))([Ee][-+]?\d+)|[-+]?INF|NaN$/) {
494 1         5 return 1;
495             } else {
496 1         8 return 0;
497             }
498             } elsif ($dt eq 'http://www.w3.org/2001/XMLSchema#boolean') {
499 0 0       0 if ($value =~ m/^(true|false)$/) {
500 0         0 return 1;
501             } else {
502 0         0 return 0;
503             }
504             } elsif ($dt eq 'http://www.w3.org/2001/XMLSchema#dateTime') {
505 0 0       0 if ($value =~ m/^-?([1-9]\d{3,}|0\d{3})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T(([01]\d|2[0-3]):[0-5]\d:[0-5]\d(\.\d+)?|(24:00:00(\.0+)?))(Z|(\+|-)((0\d|1[0-3]):[0-5]\d|14:00))?$/) {
506 0         0 return 1;
507             } else {
508 0         0 return 0;
509             }
510             }
511 0         0 return 0;
512             }
513              
514             =item C<< is_valid_lexical_form >>
515              
516             Returns true if the node is of a recognized datatype and has a valid lexical form
517             for that datatype. If the lexical form is invalid, returns false. If the datatype
518             is unrecognized, returns zero-but-true.
519              
520             =cut
521              
522             sub is_valid_lexical_form {
523 5     5 1 9 my $self = shift;
524 5         11 my $value = $self->literal_value;
525 5         12 my $dt = $self->literal_datatype;
526            
527 5 50       48 unless ($dt =~ qr<^http://www.w3.org/2001/XMLSchema#(integer|decimal|float|double|boolean|dateTime|non(Positive|Negative)Integer|(positive|negative)Integer|long|int|short|byte|unsigned(Long|Int|Short|Byte))>) {
528 0         0 return '0E0'; # zero but true (it's probably ok, but we don't recognize the datatype)
529             }
530            
531 5 50       28 if ($dt =~ m<http://www.w3.org/2001/XMLSchema#(integer|non(Positive|Negative)Integer|(positive|negative)Integer|long|int|short|byte|unsigned(Long|Int|Short|Byte))>) {
    0          
    0          
    0          
    0          
    0          
532 5 100       20 if ($value =~ m/^([-+])?(\d+)$/) {
533 3         14 return 1;
534             } else {
535 2         11 return 0;
536             }
537             } elsif ($dt eq 'http://www.w3.org/2001/XMLSchema#decimal') {
538 0 0         if ($value =~ m/^([-+])?((\d+)([.]\d*)?)$/) {
    0          
539 0           return 1;
540             } elsif ($value =~ m/^([-+])?([.]\d+)$/) {
541 0           return 1;
542             } else {
543 0           return 0;
544             }
545             } elsif ($dt eq 'http://www.w3.org/2001/XMLSchema#float') {
546 0 0         if ($value =~ m/^[-+]?(\d+(\.\d*)?|\.\d+)([Ee][-+]?\d+)?|[-+]?INF|NaN$/) {
547 0           return 1;
548             } else {
549 0           return 0;
550             }
551             } elsif ($dt eq 'http://www.w3.org/2001/XMLSchema#double') {
552 0 0         if ($value =~ m/^[-+]?((\d+(\.\d*)?)|(\.\d+))([Ee][-+]?\d+)?|[-+]?INF|NaN$/) {
553 0           return 1;
554             } else {
555 0           return 0;
556             }
557             } elsif ($dt eq 'http://www.w3.org/2001/XMLSchema#boolean') {
558 0 0         if ($value =~ m/^(true|false|0|1)$/) {
559 0           return 1;
560             } else {
561 0           return 0;
562             }
563             } elsif ($dt eq 'http://www.w3.org/2001/XMLSchema#dateTime') {
564 0 0         if ($value =~ m/^-?([1-9]\d{3,}|0\d{3})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T(([01]\d|2[0-3]):[0-5]\d:[0-5]\d(\.\d+)?|(24:00:00(\.0+)?))(Z|(\+|-)((0\d|1[0-3]):[0-5]\d|14:00))?$/) {
565 0           return 1;
566             } else {
567 0           return 0;
568             }
569             }
570 0           return 0;
571             }
572              
573             =item C<< is_numeric_type >>
574              
575             Returns true if the literal is a known (xsd) numeric type.
576              
577             =cut
578              
579             sub is_numeric_type {
580 0     0 1   my $self = shift;
581 0 0         return 0 unless ($self->has_datatype);
582 0           my $type = $self->literal_datatype;
583 0 0         if ($type =~ qr<^http://www.w3.org/2001/XMLSchema#(integer|decimal|float|double|non(Positive|Negative)Integer|(positive|negative)Integer|long|int|short|byte|unsigned(Long|Int|Short|Byte))>) {
584 0           return 1;
585             } else {
586 0           return 0;
587             }
588             }
589              
590             =item C<< numeric_value >>
591              
592             Returns the numeric value of the literal (even if the literal isn't a known numeric type.
593              
594             =cut
595              
596             sub numeric_value {
597 0     0 1   my $self = shift;
598 0 0         if ($self->is_numeric_type) {
    0          
    0          
599 0           my $value = $self->literal_value;
600 0 0         if (looks_like_number($value)) {
601 0           my $v = 0 + eval "$value"; ## no critic (ProhibitStringyEval)
602 0           return $v;
603             } else {
604 0           throw RDF::Query::Error::TypeError -text => "Literal with numeric type does not appear to have numeric value.";
605             }
606             } elsif (not $self->has_datatype) {
607 0 0         if (looks_like_number($self->literal_value)) {
608 0           return 0+$self->literal_value;
609             } else {
610 0           return;
611             }
612             } elsif ($self->literal_datatype eq 'http://www.w3.org/2001/XMLSchema#boolean') {
613 0 0         return ($self->literal_value eq 'true') ? 1 : 0;
614             } else {
615 0           return;
616             }
617             }
618              
619             1;
620              
621             __END__
622              
623             =back
624              
625             =head1 BUGS
626              
627             Please report any bugs or feature requests to through the GitHub web interface
628             at L<https://github.com/kasei/perlrdf/issues>.
629              
630             =head1 AUTHOR
631              
632             Gregory Todd Williams C<< <gwilliams@cpan.org> >>
633              
634             =head1 COPYRIGHT
635              
636             Copyright (c) 2006-2012 Gregory Todd Williams. This
637             program is free software; you can redistribute it and/or modify it under
638             the same terms as Perl itself.
639              
640             =cut