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.017
11              
12             =cut
13              
14             package RDF::Trine::Node::Literal;
15              
16 68     68   456 use strict;
  68         138  
  68         1608  
17 68     68   372 use warnings;
  68         121  
  68         1550  
18 68     68   293 no warnings 'redefine';
  68         145  
  68         1780  
19 68     68   346 use base qw(RDF::Trine::Node);
  68         142  
  68         4085  
20              
21 68     68   22024 use RDF::Trine::Error;
  68         210  
  68         597  
22 68     68   3995 use Data::Dumper;
  68         170  
  68         3139  
23 68     68   411 use Scalar::Util qw(blessed looks_like_number);
  68         194  
  68         3269  
24 68     68   385 use Carp qw(carp croak confess);
  68         152  
  68         7900  
25              
26             ######################################################################
27              
28             our ($VERSION, $USE_XMLLITERALS, $USE_FORMULAE);
29             BEGIN {
30 68     68   257 $VERSION = '1.017';
31 68     68   5151 eval "use RDF::Trine::Node::Literal::XML;"; ## no critic (ProhibitStringyEval)
  68         11012  
  0         0  
  0         0  
32 68 50       954 $USE_XMLLITERALS = (RDF::Trine::Node::Literal::XML->can('new')) ? 1 : 0;
33 68     68   3613 eval "use RDF::Trine::Node::Formula;"; ## no critic (ProhibitStringyEval)
  68         10744  
  0         0  
  0         0  
34 68 50       3540 $USE_FORMULAE = (RDF::Trine::Node::Formula->can('new')) ? 1 : 0;
35             }
36              
37             ######################################################################
38              
39 4150     4150   17329 use overload '""' => sub { $_[0]->sse },
40 68     68   412 ;
  68         144  
  68         662  
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 8135 my $class = shift;
59 2360         4142 my $literal = shift;
60 2360         4078 my $lang = shift;
61 2360         3918 my $dt = shift;
62 2360         4038 my $canon = shift;
63            
64 2360 50       6075 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     10067 if (blessed($dt) and $dt->isa('RDF::Trine::Node::Resource')) {
69 167         742 $dt = $dt->uri_value;
70             }
71            
72 2360 100 100     7527 if ($dt and $canon) {
73 25         61 $literal = $class->canonicalize_literal_value( $literal, $dt );
74             }
75            
76 2360 50 33     12425 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         7168 return $class->_new( $literal, $lang, $dt );
82             }
83             }
84              
85             sub _new {
86 2360     2360   4357 my $class = shift;
87 2360         4375 my $literal = shift;
88 2360         3716 my $lang = shift;
89 2360         4162 my $dt = shift;
90 2360         3523 my $self;
91              
92 2360 100 100     6658 if ($lang and $dt) {
93 1         19 throw RDF::Trine::Error::MethodInvocationError ( -text => "Literal values cannot have both language and datatype" );
94             }
95            
96 2359 100       7070 if ($lang) {
    100          
97 89         186 my $oldlang = $lang;
98             # http://tools.ietf.org/html/bcp47#section-2.1.1
99             # All subtags use lowercase letters
100 89         214 $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         335 $lang =~ s{(?<=\w\w-)(\w\w)(?=($|-))}{\U$1}g;
107              
108             # 2. four-letter subtags are titlecase
109 89         197 $lang =~ s{(?<=\w\w-)(\w\w\w\w)(?=($|-))}{\u\L$1}g;
110 89         293 $self = [ $literal, $lang, undef ];
111             } elsif ($dt) {
112 372 50       1340 if (blessed($dt)) {
113 0         0 $dt = $dt->uri_value;
114             }
115 372         1196 $self = [ $literal, undef, $dt ];
116             } else {
117 1898         4689 $self = [ $literal ];
118             }
119 2359         10943 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 11864     11864 1 80460 my $self = shift;
131 11864 100       28267 if (@_) {
132 1         4 $self->[0] = shift;
133             }
134 11864         33262 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 11365     11365 1 17497 my $self = shift;
145 11365         32775 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 10878     10878 1 17473 my $self = shift;
156 10878         28454 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 1102 my $self = shift;
167 590         1389 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 6295     6295 1 10642 my $self = shift;
178 6295         13588 my $literal = $self->literal_value;
179 6295         20569 my $escaped = $self->_unicode_escape( $literal );
180 6295         11389 $literal = $escaped;
181 6295 100       13250 if (defined(my $lang = $self->literal_value_language)) {
    100          
182 342         1404 return qq("${literal}"\@${lang});
183             } elsif (defined(my $dt = $self->literal_datatype)) {
184 1553         9178 return qq("${literal}"^^<${dt}>);
185             } else {
186 4400         18565 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 7724 my $self = shift;
198 3370         7703 my $string = '"' . $self->literal_value . '"';
199 3370 100       8080 if (defined(my $dt = $self->literal_datatype)) {
    100          
200 789         2341 $string .= '^^<' . $dt . '>';
201             } elsif (defined(my $lang = $self->literal_value_language)) {
202 200         415 $string .= '@' . $lang;
203             }
204 3370         11466 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 1222 my $self = shift;
215 649         1667 my $literal = $self->literal_value;
216 649         2584 my $escaped = $self->_unicode_escape( $literal );
217 649         1383 $literal = $escaped;
218 649 100       1676 if (defined(my $lang = $self->literal_value_language)) {
    100          
219 22         147 return qq("${literal}"\@${lang});
220             } elsif (defined(my $dt = $self->literal_datatype)) {
221 162         1363 return qq("${literal}"^^<${dt}>);
222             } else {
223 465         2917 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 1906 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 866 my $self = shift;
245 568 100       1027 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 234 my $self = shift;
256 108 100       289 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 47 my $self = shift;
267 17         30 my $node = shift;
268 17 100 100     169 return 0 unless (blessed($node) and $node->isa('RDF::Trine::Node::Literal'));
269 11 100       35 return 0 unless ($self->literal_value eq $node->literal_value);
270 10 100 66     27 if ($self->literal_datatype or $node->literal_datatype) {
271 68     68   64994 no warnings 'uninitialized';
  68         215  
  68         3998  
272 4 100       14 return 0 unless ($self->literal_datatype eq $node->literal_datatype);
273             }
274 9 100 66     23 if ($self->literal_value_language or $node->literal_value_language) {
275 68     68   392 no warnings 'uninitialized';
  68         186  
  68         44622  
276 3 100       9 return 0 unless ($self->literal_value_language eq $node->literal_value_language);
277             }
278 8         37 return 1;
279             }
280              
281             # called to compare two nodes of the same type
282             sub _compare {
283 144     144   358 my $a = shift;
284 144         325 my $b = shift;
285 144 50       472 if ($a->literal_value ne $b->literal_value) {
286 144         422 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 1078 my $self = shift;
313 588         1433 my $class = ref($self);
314 588         1523 my $dt = $self->literal_datatype;
315 588         1803 my $lang = $self->literal_value_language;
316 588         1541 my $value = $self->value;
317 588 100       1530 if (defined $dt) {
318 5         27 $value = RDF::Trine::Node::Literal->canonicalize_literal_value( $value, $dt, 1 );
319             }
320 588         1703 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 83 my $self = shift;
336 40         78 my $value = shift;
337 40         94 my $dt = shift;
338 40         76 my $warn = shift;
339            
340 40 100       198 if ($dt eq 'http://www.w3.org/2001/XMLSchema#integer') {
    100          
    100          
    100          
    50          
    0          
341 9 50       50 if ($value =~ m/^([-+])?(\d+)$/) {
342 9   100     44 my $sign = $1 || '';
343 9         21 my $num = $2;
344 9 100       30 $sign = '' if ($sign eq '+');
345 9         51 $num =~ s/^0+(\d)/$1/;
346 9         48 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       43 if ($value =~ m/^([-+])?((\d+)([.]\d*)?)$/) {
    0          
352 5   100     30 my $sign = $1 || '';
353 5         19 my $num = $2;
354 5         15 my $int = $3;
355 5         17 my $frac = $4;
356 5 100       24 $sign = '' if ($sign eq '+');
357 5         21 $num =~ s/^0+(.)/$1/;
358 5         43 $num =~ s/[.](\d)0+$/.$1/;
359 5 100       27 if ($num =~ /^[.]/) {
360 1         3 $num = "0$num";
361             }
362 5 50       31 if ($num !~ /[.]/) {
363 0         0 $num = "${num}.0";
364             }
365 5         33 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       42 if ($value =~ m/^(?:([-+])?(?:(\d+(?:\.\d*)?|\.\d+)([Ee][-+]?\d+)?|(INF)))|(NaN)$/) {
378 8         21 my $sign = $1;
379 8         14 my $inf = $4;
380 8         15 my $nan = $5;
381 68     68   506 no warnings 'uninitialized';
  68         158  
  68         22103  
382 8 100       26 $sign = '' if ($sign eq '+');
383 8 100       48 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         9 $sign = $1;
389 7         8 $inf = $4;
390 7         7 $nan = $5;
391 7         9 my $num = $2;
392 7         10 my $exp = $3;
393 7         32 $num =~ s/[.](\d+?)0+/.$1/;
394 7         12 $exp =~ tr/e/E/;
395 7         13 $exp =~ s/E[+]/E/;
396 7         21 $exp =~ s/E(-?)0+([1-9])$/E$1$2/;
397 7         13 $exp =~ s/E(-?)0+$/E${1}0/;
398 7         17 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       42 if ($value =~ m/^(?:([-+])?(?:(\d+(?:\.\d*)?|\.\d+)([Ee][-+]?\d+)?|(INF)))|(NaN)$/) {
408 8         21 my $sign = $1;
409 8         16 my $inf = $4;
410 8         16 my $nan = $5;
411 68     68   476 no warnings 'uninitialized';
  68         140  
  68         117749  
412 8 100       23 $sign = '' if ($sign eq '+');
413 8 100       44 return "${sign}$inf" if ($inf);
414 8 100       15 return $nan if ($nan);
415              
416 7         43 $value = sprintf('%E', $value);
417 7         19 $value =~ m/^(?:([-+])?(?:(\d+(?:\.\d*)?|\.\d+)([Ee][-+]?\d+)?|(INF)))|(NaN)$/;
418 7         10 $sign = $1;
419 7         9 $inf = $4;
420 7         9 $nan = $5;
421 7         9 my $num = $2;
422 7         11 my $exp = $3;
423 7         32 $num =~ s/[.](\d+?)0+/.$1/;
424 7         13 $exp =~ tr/e/E/;
425 7         14 $exp =~ s/E[+]/E/;
426 7         22 $exp =~ s/E(-?)0+([1-9])$/E$1$2/;
427 7         14 $exp =~ s/E(-?)0+$/E${1}0/;
428 7         19 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       60 if ($value =~ m/^(true|false|0|1)$/) {
438 10 100       34 $value = 'true' if ($value eq '1');
439 10 100       36 $value = 'false' if ($value eq '0');
440 10         32 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 50 my $self = shift;
461 24         81 my $value = $self->literal_value;
462 24         56 my $dt = $self->literal_datatype;
463            
464 24 50       248 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       176 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       105 if ($value =~ m/^([-+])?(\d+)$/) {
470 17         84 return 1;
471             } else {
472 1         6 return 0;
473             }
474             } elsif ($dt eq 'http://www.w3.org/2001/XMLSchema#decimal') {
475 3 100       18 if ($value =~ m/^([-+])?((\d+)[.]\d+)$/) {
    100          
476 1         5 return 1;
477             } elsif ($value =~ m/^([-+])?([.]\d+)$/) {
478 1         5 return 1;
479             } else {
480 1         7 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       26 if ($value =~ m/^[-+]?((\d+(\.\d*))|(\.\d+))([Ee][-+]?\d+)?|[-+]?INF|NaN$/) {
    100          
492 1         6 return 1;
493             } elsif ($value =~ m/^[-+]?((\d+(\.\d*)?)|(\.\d+))([Ee][-+]?\d+)|[-+]?INF|NaN$/) {
494 1         8 return 1;
495             } else {
496 1         6 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 10 my $self = shift;
524 5         13 my $value = $self->literal_value;
525 5         13 my $dt = $self->literal_datatype;
526            
527 5 50       57 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       33 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       18 if ($value =~ m/^([-+])?(\d+)$/) {
533 3         18 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