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