1# -*- Mode: Perl -*-
2#
3# Node.pm - Redland Perl RDF Node module
4#
5# Copyright (C) 2000-2005 David Beckett - http://www.dajobe.org/
6# Copyright (C) 2000-2005 University of Bristol - http://www.bristol.ac.uk/
7#
8# This package is Free Software and part of Redland http://librdf.org/
9#
10# It is licensed under the following three licenses as alternatives:
11#   1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
12#   2. GNU General Public License (GPL) V2 or any newer version
13#   3. Apache License, V2.0 or any newer version
14#
15# You may not use this file except in compliance with at least one of
16# the above three licenses.
17#
18# See LICENSE.html or LICENSE.txt at the top of this package for the
19# full license terms.
20#
21#
22#
23
24package RDF::Redland::Node;
25
26use strict;
27use Encode;
28
29use vars qw($Type_Resource $Type_Property $Type_Literal
30	    $Type_Statement $Type_Blank);
31
32# FIXME: Should be the same as values of librdf_node_type enum in rdf_node.h
33# and mechanically kept in sync.
34$Type_Resource  = 1;
35$Type_Literal   = 2;
36$Type_Blank     = 4;
37# FIXME: Needs to also match documentation near sub type
38
39
40
41=pod
42
43=head1 NAME
44
45RDF::Redland::Node - Redland RDF Node (RDF Resource, Property, Literal) Class
46
47=head1 SYNOPSIS
48
49  use RDF::Redland;
50  my $node1=new RDF::Redland::Node("Hello, World!");
51  my $node2=new RDF::Redland::Node($uri); # $uri is an RDF::Redland::URI
52  my $node3=$node2->clone;
53
54  my $node4=new RDF::Redland::URINode("http://example.com/");
55  my $node5=new RDF::Redland::LiteralNode("Hello, World!");
56  my $node6=new RDF::Redland::XMLLiteral("<tag>content</tag>");
57  my $node7=new RDF::Redland::BlankNode("genid1");
58
59  # alternate more verbose ways:
60  my $node4=RDF::Redland::Node->new_from_uri("http://example.com/");
61  my $node5=RDF::Redland::Node->new_literal("Hello, World!");
62  my $node6=RDF::Redland::Node->new_xml_literal("<tag>content</tag>");
63  my $node7=RDF::Redland::Node->new_from_blank_identifier("genid1");
64  ...
65
66  print $node4->uri->as_string,"\n";  # Using RDF::Redland::URI::as_string
67  print $node5->literal_value_as_latin1,"\n";
68
69=head1 DESCRIPTION
70
71This class represents RDF URIs, literals and blank nodes in the RDF graph.
72
73=cut
74
75######################################################################
76
77=pod
78
79=head1 CONSTRUCTORS
80
81=over
82
83=item new [STRING | URI | NODE]
84
85Create a new URI node, literal node or copy an existing node.
86
87If a literal I<STRING> is given, make a plain literal node.  If a
88the argument is of type I<URI> (perl URI or RDF::Redland::URI),
89make a resource node.
90
91Otherwise if the argument is an RDF::Redland::Node I<NODE>, copy it.
92
93=cut
94
95
96# CONSTRUCTOR
97# (main)
98sub new ($;$) {
99  my($proto,$arg)=@_;
100  my $class = ref($proto) || $proto;
101  my $self  = {};
102
103  if($arg) {
104    if(my $arg_class=ref($arg)) {
105      # Try several classes
106      if(UNIVERSAL::isa($arg, 'RDF::Redland::Node')) {
107        return $arg->clone;
108      } elsif(UNIVERSAL::isa($arg, 'RDF::Redland::URI')) {
109        $self->{NODE}=&RDF::Redland::CORE::librdf_new_node_from_uri_string($RDF::Redland::World->{WORLD},$arg->as_string);
110      } elsif (UNIVERSAL::isa($arg, 'URI')) {
111	$self->{NODE}=&RDF::Redland::CORE::librdf_new_node_from_uri_string($RDF::Redland::World->{WORLD},$arg->as_string);
112      } else {
113	die "RDF::Redland::Node::new - Cannot make a node from an object of class $arg_class\n";
114      }
115    } else {
116      # Not a class
117      $self->{NODE}=&RDF::Redland::CORE::librdf_new_node_from_typed_literal($RDF::Redland::World->{WORLD},$arg,'',undef);
118    }
119  } else {
120    $self->{NODE}=&RDF::Redland::CORE::librdf_new_node($RDF::Redland::World->{WORLD});
121  }
122  return undef if !$self->{NODE};
123
124  bless ($self, $class);
125  return $self;
126}
127
128sub new_from_uri_string ($$) {
129  my($proto,$uri_string)=@_;
130  my $class = ref($proto) || $proto;
131  my $self  = {};
132  die "RDF::Redland::Node::new_from_uri_string - Cannot create node from empty URI\n"
133    unless $uri_string;
134
135  $self->{NODE}=&RDF::Redland::CORE::librdf_new_node_from_uri_string($RDF::Redland::World->{WORLD},$uri_string);
136  return undef if !$self->{NODE};
137
138  bless ($self, $class);
139  return $self;
140}
141
142=item new_from_uri URI
143
144Create a new URI node.  I<URI> can be either a RDF::Redland::URI
145object, a perl URI class or a literal string.
146
147An alternative is:
148
149  new RDF::Redland::URINode("http://example.org/");
150
151=cut
152
153sub new_from_uri ($$) {
154  my($proto,$arg)=@_;
155  my $class = ref($proto) || $proto;
156  my $self  = {};
157  if(my $class=ref $arg) {
158    if(UNIVERSAL::isa($arg, 'RDF::Redland::URI')) {
159      $self->{NODE}=&RDF::Redland::CORE::librdf_new_node_from_uri($RDF::Redland::World->{WORLD},$arg->{URI});
160    } elsif (UNIVERSAL::isa($arg, 'URI')) {
161      $self->{NODE}=&RDF::Redland::CORE::librdf_new_node_from_uri_string($RDF::Redland::World->{WORLD},$arg->as_string);
162    } else {
163      die "RDF::Redland::Node::new_from_uri - Cannot make a Node from an object of class $class\n";
164    }
165  } else {
166    $self->{NODE}=&RDF::Redland::CORE::librdf_new_node_from_uri_string($RDF::Redland::World->{WORLD},$arg);
167  }
168  return undef if !$self->{NODE};
169
170  bless ($self, $class);
171  return $self;
172}
173
174
175sub new_from_literal ($$$$) {
176  my($proto,$string,$xml_language,$is_wf_xml)=@_;
177  my $class = ref($proto) || $proto;
178  my $self  = {};
179  $is_wf_xml=($is_wf_xml ? 1 : 0);
180  $self->{NODE}=&RDF::Redland::CORE::librdf_new_node_from_literal($RDF::Redland::World->{WORLD},$string,$xml_language,$is_wf_xml);
181  return undef if !$self->{NODE};
182
183  bless ($self, $class);
184  return $self;
185}
186
187=item new_literal STRING [DATATYPE [XML_LANGUAGE]]
188
189Create a new literal node for a literal value I<STRING>.
190Optional datatype URI I<DATATYPE> (RDF::Redland::URI, perl URI or string)
191and language (xml:lang attribute) I<XML_LANGUAGE> may also be given.
192
193An alternative is:
194
195   new RDF::Redland::LiteralNode("Hello, World!");
196   new RDF::Redland::LiteralNode("Bonjour monde!", undef, "fr");
197
198
199=cut
200
201sub new_literal ($$;$$) {
202  my($proto,$string,$dt,$xml_language)=@_;
203  my $class = ref($proto) || $proto;
204  my $self  = {};
205  my $dt_uri=undef;
206  if(defined $dt) {
207    if(UNIVERSAL::isa($dt, 'RDF::Redland::URI')) {
208      # nop
209    } elsif (UNIVERSAL::isa($dt, 'URI')) {
210      $dt=RDF::Redland::URI->new($dt->as_string);
211    } else {
212      $dt=RDF::Redland::URI->new($dt);
213    }
214    $dt_uri=$dt->{URI};
215  }
216
217  $self->{NODE}=&RDF::Redland::CORE::librdf_new_node_from_typed_literal($RDF::Redland::World->{WORLD},$string,$xml_language,$dt_uri);
218  return undef if !$self->{NODE};
219
220  bless ($self, $class);
221  return $self;
222}
223
224=item new_xml_literal STRING
225
226Create a new XML datatyped literal node for the XML in I<STRING>.
227
228An alternative is:
229
230  new RDF::Redland::XMLLiteral("<tag>content</tag>");
231
232=cut
233
234sub new_xml_literal ($$) {
235  my($proto,$string)=@_;
236  return $proto->new_from_literal($string,'',1);
237}
238
239
240=item new_from_blank_identifier IDENTIFIER
241
242Create a new blank node with blank node identifier I<IDENTIFIER>.
243
244An alternative is:
245
246  new RDF::Redland::BlankNode("id");
247
248=cut
249
250sub new_from_blank_identifier ($;$) {
251  my($proto,$identifier)=@_;
252  my $class = ref($proto) || $proto;
253  my $self  = {};
254  $self->{NODE}=&RDF::Redland::CORE::librdf_new_node_from_blank_identifier($RDF::Redland::World->{WORLD},$identifier);
255  return undef if !$self->{NODE};
256
257  bless ($self, $class);
258  return $self;
259}
260
261
262=item clone
263
264Copy a RDF::Redland::Node.
265
266=cut
267
268sub clone ($) {
269  my($node)=@_;
270  my $class = ref($node);
271  my $self  = {};
272
273  if(!$class || $class ne 'RDF::Redland::Node') {
274    die "RDF::Redland::Node::clone - Cannot copy a node object not of class RDF::Redland::Node\n";
275  }
276
277  $self->{NODE}=&RDF::Redland::CORE::librdf_new_node_from_node($node->{NODE});
278  return undef if !$self->{NODE};
279
280  bless ($self, $class);
281  return $self;
282}
283
284sub new_from_node ($$) {
285  my($proto,$node)=@_;
286  return $node->clone;
287}
288
289# internal constructor to build an object from a node created
290# by librdf e.g. from the result of a iterator->next operation
291# It always makes a new Redland Node
292sub _new_from_object ($$;$) {
293  my($proto,$object,$do_not_copy)=@_;
294  return undef if !$object;
295  my $class = ref($proto) || $proto;
296  my $self  = {};
297
298  $self->{NODE}=$do_not_copy ? $object : &RDF::Redland::CORE::librdf_new_node_from_node($object);
299  bless ($self, $class);
300  return $self;
301}
302
303=pod
304
305=back
306
307=cut
308
309# DESTRUCTOR
310sub DESTROY ($) {
311  my $self=shift;
312  warn "RDF::Redland::Node DESTROY $self" if $RDF::Redland::Debug;
313  if($self->{NODE}) {
314    &RDF::Redland::CORE::librdf_free_node($self->{NODE});
315  }
316  warn "RDF::Redland::Node DESTROY done\n" if $RDF::Redland::Debug;
317}
318
319
320=head1 METHODS
321
322=over
323
324=item uri
325
326Get the current URI of the node as an RDF::Redland::URI object.
327
328=cut
329
330sub uri ($) {
331  my $obj=&RDF::Redland::CORE::librdf_node_get_uri(shift->{NODE});
332  return $obj ?  RDF::Redland::URI->_new_from_object($obj) : undef;
333}
334
335=item blank_identifier
336
337Get the current blank identifier of the node
338
339=cut
340
341sub blank_identifier ($) {
342  return &RDF::Redland::CORE::librdf_node_get_blank_identifier(shift->{NODE});
343}
344
345=item type
346
347Get the node type.  It is recommended to use the is_resource, is_literal
348or is_blank methods in preference to this (both simpler and quicker).
349
350The current list of types that are supported are:
351
352  $RDF::Redland::Node::Type_Resource
353  $RDF::Redland::Node::Type_Literal
354  $RDF::Redland::Node::Type_Blank
355
356Example:
357
358  if ($node->type == $RDF::Redland::Node::Type_Resource) {
359    print "Node is a resource with URI ", $node->uri->as_string, "\n";
360  } else {
361    ...
362  }
363
364=cut
365
366sub type ($) {
367  return &RDF::Redland::CORE::librdf_node_get_type(shift->{NODE});
368}
369
370=item is_resource
371
372Return true if node is a resource (with a URI)
373
374=cut
375sub is_resource($) {
376  return &RDF::Redland::CORE::librdf_node_is_resource(shift->{NODE});
377}
378
379=item is_literal
380
381Return true if node is a literal
382
383=cut
384sub is_literal($) {
385  return &RDF::Redland::CORE::librdf_node_is_literal(shift->{NODE});
386}
387
388=item is_blank
389
390Return true if node is a blank nodeID
391
392=cut
393sub is_blank($) {
394  return &RDF::Redland::CORE::librdf_node_is_blank(shift->{NODE});
395}
396
397=item literal_value
398
399Get the node literal value string as UTF-8 (when the node is of type
400$RDF::Redland::Node::Type_Literal)
401
402=cut
403
404sub literal_value ($) {
405  return decode_utf8(&RDF::Redland::CORE::librdf_node_get_literal_value(shift->{NODE}));
406}
407
408=item literal_value_as_latin1
409
410Get the node literal value string converted from UTF-8 to ISO Latin-1
411(when the node is of type $RDF::Redland::Node::Type_Literal)
412
413=cut
414
415sub literal_value_as_latin1 ($) {
416  &RDF::Redland::CORE::librdf_node_get_literal_value_as_latin1(shift->{NODE});
417}
418
419=item literal_value_language
420
421Get the node literal XML language (when the node is of type
422$RDF::Redland::Node::Type_Literal) or undef if not present.
423
424=cut
425
426sub literal_value_language ($) {
427  &RDF::Redland::CORE::librdf_node_get_literal_value_language(shift->{NODE});
428}
429
430=item literal_value_is_wf_xml
431
432Return non 0 if the literal string is well formed XML (when the node
433is of type $RDF::Redland::Node::Type_Literal).
434
435=cut
436
437sub literal_value_is_wf_xml ($) {
438  &RDF::Redland::CORE::librdf_node_get_literal_value_is_wf_xml(shift->{NODE});
439}
440
441=item literal_datatype
442
443Return the RDF::Redland::URI of the literal datatype or undef if it
444is not a datatype.
445
446=cut
447
448sub literal_datatype($) {
449  my $self=shift;
450  my $uri=&RDF::Redland::CORE::librdf_node_get_literal_value_datatype_uri($self->{NODE});
451  return $uri ? RDF::Redland::URI->new(&RDF::Redland::CORE::librdf_uri_to_string($uri)) : undef;
452}
453
454=item as_string
455
456Return the RDF::Redland::Node formatted as a string (UTF-8 encoded).
457
458=cut
459
460sub as_string ($) {
461  my $v = decode_utf8(&RDF::Redland::CORE::librdf_node_to_string(shift->{NODE}));
462  return $v;
463}
464
465=item equals NODE
466
467Return non zero if this node is equal to NODE
468
469=cut
470
471sub equals ($$) {
472  my($self,$node)=@_;
473  &RDF::Redland::CORE::librdf_node_equals($self->{NODE}, $node->{NODE});
474}
475
476
477# Ensure the thing given is a Redland node, promoting it if possible
478# from other perl objects.
479sub _ensure ($) {
480  my $node=shift;
481  if(UNIVERSAL::isa($node, 'RDF::Redland::Node')) {
482    $node=&RDF::Redland::CORE::librdf_new_node_from_node($node->{NODE});
483  } elsif(UNIVERSAL::isa($node, 'RDF::Redland::URI')) {
484    $node=&RDF::Redland::CORE::librdf_new_node_from_uri($RDF::Redland::World->{WORLD},$node->{URI});
485  } elsif (UNIVERSAL::isa($node, 'URI')) {
486    $node=&RDF::Redland::CORE::librdf_new_node_from_uri_string($RDF::Redland::World->{WORLD},$node->as_string);
487  } else {
488    $node=undef;
489  }
490  return $node;
491}
492
493
494=pod
495
496=back
497
498=head1 OLDER METHODS
499
500=over
501
502=item new_from_literal STRING XML_LANGUAGE IS_WF
503
504Create a new RDF::Redland::Node object for a literal value I<STRING> with XML
505language (xml:lang attribute) I<XML_LANGUAGE>
506and if content is well formed XML, when I<IS_WF> is non
5070.  I<XML_LANGUAGE> is optional can can be set to undef.
508
509This method remains but using new_literal is preferred.
510Instead, for plain literals use:
511
512  $node=new RDF::Redland::Node("blah")
513
514=item new_from_typed_literal STRING [DATATYPE [XML_LANGUAGE]]
515
516Renamed to new_literal with same arguments.
517
518=item new_from_uri_string URI_STRING
519
520Create a new RDF::Redland::Node object for a resource with URI I<URI_STRING>.
521It is equivalent to use the shorter:
522
523  $a=new RDF::Redland::Node->new_from_uri($uri_string)
524
525=item new_from_node NODE
526
527Create a new RDF::Redland::Node object from existing
528RDF::Redland::Node I<NODE> (copy constructor).
529It is equivalent to use:
530
531  $new_node=$old_node->clone
532
533=back
534
535
536=head1 SEE ALSO
537
538L<RDF::Redland::Statement>
539
540=head1 AUTHOR
541
542Dave Beckett - http://www.dajobe.org/
543
544=cut
545
5461;
547