<?php
#
# librdfutil - a set of utility functions for Redland and the Redland MySQL
# storage engine.
#
# <URL: http://www.wasab.dk/morten/blog/archives/2004/09/19/librdfutil >
#
# Changelog
# ---------
# Version 0.0.1 - 2004.09.19:
# - First public release, thanks to Russell for initial thoughts (morten@mfd-consult.dk).
# Version 0.0.0 - 2004.09.14:
# - First release (morten@mfd-consult.dk).
#
# Copyright (c) 2004 MFD Consult, Morten Frederiksen
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
define('LIBRDFUTIL_NODETYPE_RESOURCE', 1);
define('LIBRDFUTIL_NODETYPE_LITERAL', 2);
define('LIBRDFUTIL_NODETYPE_BNODE', 4);
/**
* librdfutil_mysql_cbd_original_lite: Add the basic CBD (without reification) for a node object to a model.
* @node: a librdf_node object (or a PHP array of librdf_node objects)
* @model: a librdf_model object
* @modelname: (optional) name of model, otherwise all models in store will be queried.
*
* Returns number of statements added to model.
*
* Depends on global variable $db being an open ADODB connection to the
* right database.
*
* This functions returns statements according to the first two steps of
* the original CBD definition:
* 1. All statements where the subject of the statement denotes the resource
* in question; and
* 2. Recursively, for all statements included in the description thus far,
* for all anonymous node objects, all statements where the subject of the
* statement denotes anonymous resource in question
*
**/
function librdfutil_mysql_cbd_original_lite($nodes, $model, $modelname='') {
global $db;
# Compute model hash?
if ($modelname!='')
$modelname=librdfutil_strings_to_hash($modelname);
# Array of nodes?
if (!is_array($nodes))
$nodes=array($nodes);
# Get hash for each subject node.
$hashes=array();
$uris=array();
$bnodes=array();
foreach ($nodes as $node) {
$type=librdf_node_get_type($node);
if ($type==LIBRDFUTIL_NODETYPE_RESOURCE)
$uris[]=librdf_uri_to_string(librdf_node_get_uri($node));
elseif ($type==LIBRDFUTIL_NODETYPE_BNODE)
$bnodes[]=librdf_node_get_blank_identifier($node);
}
$sql='SELECT ID FROM Resources WHERE URI="'.join('" OR URI="', $uris).'"';
if ($records=$db->Execute($sql)) {
while ($record=$records->FetchRow())
$hashes[$record['ID']]=1;
}
$sql='SELECT ID FROM Bnodes WHERE Name="'.join('" OR Name="', $bnodes).'"';
if ($records=$db->Execute($sql)) {
while ($record=$records->FetchRow())
$hashes[$record['ID']]=1;
}
# Start loop to find bnode objects.
$nodecount=sizeof($hashes);
do {
$lastnodecount=$nodecount;
$sql='SELECT DISTINCT ID
FROM Statements'.$modelname.' JOIN Bnodes ON Object=ID
WHERE Subject='.join(' OR Subject=', array_keys($hashes));
if ($records=$db->Execute($sql)) {
while ($record=$records->FetchRow()) {
$hashes[$record['ID']]=1;
}
}
$nodecount=sizeof($hashes);
} while ($nodecount!=$lastnodecount);
# Find statements about nodes in list.
$sql='SELECT DISTINCT SubjectR.URI AS SuR, SubjectB.Name AS SuB,
PredicateR.URI AS PrR, ObjectR.URI AS ObR, ObjectB.Name as ObB,
ObjectL.Value AS ObV, ObjectL.Language AS ObL, ObjectL.Datatype AS ObD
FROM Statements
JOIN Resources AS PredicateR ON Predicate=PredicateR.ID
LEFT JOIN Resources AS SubjectR ON Subject=SubjectR.ID
LEFT JOIN Bnodes AS SubjectB ON Subject=SubjectB.ID
LEFT JOIN Resources AS ObjectR ON Object=ObjectR.ID
LEFT JOIN Bnodes AS ObjectB ON Object=ObjectB.ID
LEFT JOIN Literals AS ObjectL ON Object=ObjectL.ID
WHERE Subject='.join(' OR Subject=', array_keys($hashes));
$statementcount=0;
if ($records=$db->Execute($sql)) {
while ($record=$records->FetchRow()) {
librdf_model_add_statement($model, librdfutil_tuple_to_statement($record));
$statementcount++;
}
}
# Return number of statements added to model.
return $statementcount;
}
/**
* librdfutil_mysql_cbd_lite: Add revised CBD (without reification) for a node object to a model.
* @node: a librdf_node object (or a PHP array of librdf_node objects)
* @model: a librdf_model object
* @modelname: (optional) name of model, otherwise all models in store will be queried.
* @labels: (optional) boolean indicating whether label and type properties should be included for IFP identified bnodes, default is false.
*
* Returns number of statements added to model.
*
* Depends on global variable $db being an open ADODB connection to the
* right database.
*
* This functions returns statements according to the first two steps of
* the revised CBD definition, including IFBD retrieval, optionally augmented
* with rdfs:label (and rdf:type) statements.
*
**/
function librdfutil_mysql_cbd_lite($nodes, $model, $modelname='', $labels=false) {
global $db;
# Compute model hash?
if ($modelname!='')
$modelname=librdfutil_strings_to_hash($modelname);
# Array of nodes?
if (!is_array($nodes))
$nodes=array($nodes);
# Initialize arrays with hashes for nodes.
$cbdnodes=array();
$cnodes=array();
$ifbdnodes=array();
$inodes=array();
$uris=array();
$bnodes=array();
foreach ($nodes as $node) {
$type=librdf_node_get_type($node);
if ($type==LIBRDFUTIL_NODETYPE_RESOURCE)
$uris[]=librdf_uri_to_string(librdf_node_get_uri($node));
elseif ($type==LIBRDFUTIL_NODETYPE_BNODE)
$bnodes[]=librdf_node_get_blank_identifier($node);
}
$sql='SELECT ID FROM Resources WHERE URI="'.join('" OR URI="', $uris).'"';
if ($records=$db->Execute($sql)) {
while ($record=$records->FetchRow()) {
$cbdnodes[$record['ID']]=1;
$cnodes[$record['ID']]=1;
}
}
$sql='SELECT ID FROM Bnodes WHERE Name="'.join('" OR Name="', $bnodes).'"';
if ($records=$db->Execute($sql)) {
while ($record=$records->FetchRow()) {
$cbdnodes[$record['ID']]=1;
$cnodes[$record['ID']]=1;
}
}
# Start loop to find objects of statements to retrieve.
while (sizeof($cnodes) || sizeof($inodes)) {
# Find bnodes objects and whether to limit to IFBD.
if (sizeof($cnodes)) {
$sql='SELECT ID as Object, count(S3.Object) as IFP
FROM Statements'.$modelname.' as S1
JOIN Bnodes ON S1.Object=ID
LEFT JOIN Statements'.$modelname.' as S2 on S1.Object=S2.Subject
LEFT JOIN Statements'.$modelname.' as S3 on S2.Predicate=S3.Subject
AND S3.Predicate=2982895206037061277 AND S3.Object=3893664417957479913
WHERE S1.Subject='.join(' OR S1.Subject=', array_keys($cnodes)).'
GROUP BY Object';
$cnodes=array();
if ($records=$db->Execute($sql)) {
while ($record=$records->FetchRow()) {
# New node?
if (!array_key_exists($record['Object'], $cbdnodes)
&& !array_key_exists($record['Object'], $ifbdnodes)) {
# Should the node result in only IFBD?
if ($record['IFP']) {
$ifbdnodes[$record['Object']]=1;
$inodes[$record['Object']]=1;
} else {
$cbdnodes[$record['Object']]=1;
$cnodes[$record['Object']]=1;
}
}
}
}
}
if (sizeof($inodes)) {
$sql='SELECT DISTINCT ID as Object
FROM Statements'.$modelname.' as S1
JOIN Bnodes ON S1.Object=ID
JOIN Statements'.$modelname.' as S2 on S1.Object=S2.Subject
JOIN Statements'.$modelname.' as S3 on S2.Predicate=S3.Subject
AND S3.Predicate=2982895206037061277 AND S3.Object=3893664417957479913
WHERE S1.Subject='.join(' OR S1.Subject=', array_keys($inodes));
$inodes=array();
if ($records=$db->Execute($sql)) {
while ($record=$records->FetchRow()) {
# New node?
if (!array_key_exists($record['Object'], $cbdnodes
&& !array_key_exists($record['Object'], $ifbdnodes))) {
$ifbdnodes[$record['Object']]=1;
$inodes[$record['Object']]=1;
}
}
}
}
}
# Find CBD's.
$statementcount=0;
if (sizeof($cbdnodes)) {
$sql='SELECT DISTINCT SubjectR.URI AS SuR, SubjectB.Name AS SuB,
PredicateR.URI AS PrR, ObjectR.URI AS ObR, ObjectB.Name as ObB,
ObjectL.Value AS ObV, ObjectL.Language AS ObL, ObjectL.Datatype AS ObD
FROM Statements'.$modelname.'
JOIN Resources AS PredicateR ON Predicate=PredicateR.ID
LEFT JOIN Resources AS SubjectR ON Subject=SubjectR.ID
LEFT JOIN Bnodes AS SubjectB ON Subject=SubjectB.ID
LEFT JOIN Resources AS ObjectR ON Object=ObjectR.ID
LEFT JOIN Bnodes AS ObjectB ON Object=ObjectB.ID
LEFT JOIN Literals AS ObjectL ON Object=ObjectL.ID
WHERE Subject='.join(' OR Subject=', array_keys($cbdnodes));
if ($records=$db->Execute($sql)) {
while ($record=$records->FetchRow()) {
librdf_model_add_statement($model, librdfutil_tuple_to_statement($record));
$statementcount++;
}
}
}
# Find IFBD's.
if (sizeof($ifbdnodes)) {
# Restrict to IFP statements, possibly also labels.
$restriction='AND (S2.Predicate=2982895206037061277 AND S2.Object=3893664417957479913';
if ($labels) {
# Also extract rdfs:label statements.
$restriction.=' OR S2.Subject=3108168581889151792';
# ... and statements with sub properties of rdfs:label for now (inference needed...).
$restriction.=' OR S2.Predicate=17837177236827776084 AND S2.Object=3108168581889151792';
# ... and rdf:type statements.
$restriction.=' OR S2.Subject=2982895206037061277';
}
$restriction.=')';
$sql='SELECT DISTINCT SubjectR.URI AS SuR, SubjectB.Name AS SuB,
PredicateR.URI AS PrR, ObjectR.URI AS ObR, ObjectB.Name as ObB,
ObjectL.Value AS ObV, ObjectL.Language AS ObL, ObjectL.Datatype AS ObD
FROM Statements'.$modelname.' as S1
JOIN Statements'.$modelname.' as S2 on S1.Predicate=S2.Subject
'.$restriction.'
JOIN Resources AS PredicateR ON S1.Predicate=PredicateR.ID
LEFT JOIN Resources AS SubjectR ON S1.Subject=SubjectR.ID
LEFT JOIN Bnodes AS SubjectB ON S1.Subject=SubjectB.ID
LEFT JOIN Resources AS ObjectR ON S1.Object=ObjectR.ID
LEFT JOIN Bnodes AS ObjectB ON S1.Object=ObjectB.ID
LEFT JOIN Literals AS ObjectL ON S1.Object=ObjectL.ID
WHERE S1.Subject='.join(' OR S1.Subject=', array_keys($ifbdnodes));
if ($records=$db->Execute($sql)) {
while ($record=$records->FetchRow()) {
librdf_model_add_statement($model, librdfutil_tuple_to_statement($record));
$statementcount++;
}
}
}
# Return number of statements added to model.
return $statementcount;
}
/**
* librdfutil_strings_to_node: Create a new librdf_node from a set of strings.
* @value: an NTriple formatted string (_:bnode, <URI> or "literal", quotes for literals optional)
* @language: literal language value
* @datatype: literal datatype URI
*
**/
function librdfutil_strings_to_node($value, $language='', $datatype='')
{
$world=librdf_php_get_world();
if (preg_match('|^_:(.+)$|', $value, $M))
$N=librdf_new_node_from_blank_identifier($world, $M[1]);
elseif (preg_match('|^<(.+)>$|', $value, $M))
$N=librdf_new_node_from_uri_string($world, $M[1]);
else {
if (preg_match('|^"("")?(.+)"("")?$|', $value, $M))
$value=$M[2];
if ($datatype!='') {
$D=librdf_new_uri($world, $datatype);
$N=librdf_new_node_from_typed_literal($world, $value, '', $D);
librdf_free_uri($D);
} else
$N=librdf_new_node_from_literal($world, $value, $language);
}
return $N;
}
/**
* librdfutil_stringset_to_statement: Create a new librdf_statement from a set of strings.
* @subject: an NTriple formatted string (_:bnode or <URI>)
* @predicate: an NTriple formatted string (<URI>)
* @value: an NTriple formatted string (_:bnode, <URI> or "literal", quotes for literals optional)
* @language: (optional) object literal language value
* @datatype: (optional) object literal datatype URI
*
**/
function librdfutil_stringset_to_statement($subject, $predicate, $object, $language='', $datatype='') {
$s=librdfutil_strings_to_node($subject);
$p=librdfutil_strings_to_node($predicate);
$o=librdfutil_strings_to_node($object, $language, $datatype);
if ($s && librdf_node_get_type($s)!=LIBRDFUTIL_NODETYPE_LITERAL && $p
&& librdf_node_get_type($p)==LIBRDFUTIL_NODETYPE_RESOURCE && $o)
return librdf_new_statement_from_nodes(librdf_php_get_world(), $s, $p, $o);
return 0;
}
/**
* librdfutil_tuple_to_statement: Create a new librdf_statement from a database tuple.
* @tuple: a PHP array of with 8 elements, some of them possibly empty, in the following order (preference order is URI, Bnode, Literal):
* - URI for subject node
* - Name of bnode for subject node
* - URI for predicate node
* - URI for object node
* - Name of bnode for object node
* - Literal value for object node
* - Literal language value for object node
* - Literal datatype URI for object node
*
**/
function librdfutil_tuple_to_statement($tuple) {
$world=librdf_php_get_world();
# Check input.
if (sizeof($tuple)<8)
return 0;
# Create subject node.
if ($uri=array_shift($tuple)) {
$s=librdf_new_node_from_uri_string($world, $uri);
array_shift($tuple);
} else
$s=librdf_new_node_from_blank_identifier($world, array_shift($tuple));
# Create predicate node.
$p=librdf_new_node_from_uri_string($world, array_shift($tuple));
# Create object node.
if ($uri=array_shift($tuple)) {
$o=librdf_new_node_from_uri_string($world, $uri);
array_shift($tuple);
array_shift($tuple);
array_shift($tuple);
array_shift($tuple);
} elseif ($bnode=array_shift($tuple)) {
$o=librdf_new_node_from_blank_identifier($world, $bnode);
array_shift($tuple);
array_shift($tuple);
array_shift($tuple);
} else {
$value=array_shift($tuple);
if ($lang=array_shift($tuple)) {
$o=librdf_new_node_from_literal($world, $value, $lang, 0);
array_shift($tuple);
} elseif ($dturi=array_shift($tuple))
$o=librdf_new_node_from_typed_literal($world, $value, '', librdf_new_uri($world, $dturi));
else
$o=librdf_new_node_from_literal($world, $value, '', 0);
}
# Create and return statement.
return librdf_new_statement_from_nodes($world, $s, $p, $o);
}
/**
* librdfutil_model_to_string: Get a serialised representation of a model, in R3X or Turtle syntax.
* @model: a librdf_model
* @syntax: (optional) output syntax, 'r3x' (default) or 'turtle'
* @ns: (optional) PHP associative array with prefix=>namespace mappings for QNames.
* @options: (optional) PHP array with Turtle serialisation options:
* - multiline: Generate multiline literals with triple-quotes
* - noescape: Don't escape Unicode characters
*
* NOTE: No @prefix keyword statements will be made for turtle output.
*
**/
function librdfutil_model_to_string($model, $syntax='r3x', $ns=array(), $options=array()) {
if (!($stream=librdf_model_as_stream($model)))
return '';
$output=librdfutil_stream_to_string($stream, $syntax, $ns, $options);
librdf_free_stream($stream);
return $output;
}
/**
* librdfutil_stream_to_string: Get a serialised representation of a stream of statements, in R3X or Turtle syntax.
* @stream: a librdf_stream
* @syntax: (optional) output syntax, 'r3x' (default) or 'turtle'
* @ns: (optional) PHP associative array with prefix=>namespace mappings for QNames.
* @options: (optional) PHP array with Turtle serialisation options:
* - multiline: Generate multiline literals with triple-quotes
* - noescape: Don't escape Unicode characters
*
* NOTE: No @prefix keyword statements will be made for turtle output.
*
**/
function librdfutil_stream_to_string($stream, $syntax='r3x', $ns=array(), $options=array()) {
if ($syntax=='turtle') {
$turtle='';
while (!librdf_stream_end($stream)) {
$statement=librdf_stream_get_object($stream);
$turtle.=librdfutil_node_to_turtle_string(librdf_statement_get_subject($statement), $ns, $options);
$turtle.=librdfutil_node_to_turtle_string(librdf_statement_get_predicate($statement), $ns, $options);
$turtle.=librdfutil_node_to_turtle_string(librdf_statement_get_object($statement), $ns, $options);
$turtle.=".\n";
librdf_stream_next($stream);
}
return $turtle;
}
$spgroups=array();
# Initialise prefix list, always include RDF/XML namespace.
$prefixes=array();
$rdfns='';
foreach (array_keys($ns) as $prefix) {
if ($ns[$prefix]=='http://www.w3.org/1999/02/22-rdf-syntax-ns#') {
$prefixes[$prefix]='http://www.w3.org/1999/02/22-rdf-syntax-ns#';
$rdfns=$prefix;
break;
}
}
if (!$rdfns) {
$prefixes['rdf']='http://www.w3.org/1999/02/22-rdf-syntax-ns#';
$rdfns='rdf';
}
# Generate statements by subject.
while (!librdf_stream_end($stream)) {
$statement=librdf_stream_get_object($stream);
# Construct subject.
$subject=librdf_statement_get_subject($statement);
if (librdf_node_get_type($subject)==4)
$subject='rdf:nodeID="'.htmlspecialchars(librdf_node_get_blank_identifier($subject)).'"';
else
$subject='rdf:about="'.htmlspecialchars(librdf_uri_to_string(librdf_node_get_uri($subject))).'"';
# Construct predicate.
$predicate=librdf_uri_to_string(librdf_node_get_uri(librdf_statement_get_predicate($statement)));
$qname='';
# Look for existing prefix.
foreach (array_keys($ns) as $prefix) {
$pos=strpos($predicate, $ns[$prefix]);
if ($pos===0) {
$localname=substr($predicate, strlen($ns[$prefix]));
# Make sure only NameChars are present in local part.
if (!preg_match('|[^A-Za-z_0-9-]|', $localname)) {
$qname=$prefix.':'.$localname;
$prefixes[$prefix]=$ns[$prefix];
break;
}
}
}
# Try to split into prefix and local part.
if (!$qname &&
preg_match('|^(.+?)([A-Za-z_]([A-Za-z_0-9-]+)?)$|', $predicate, $P)) {
$prefix='ns'.count($prefixes);
$prefixes[$prefix]=$P[1];
$ns[$prefix]=$P[1];
$qname=$prefix.':'.$P[2];
}
if ($qname) {
# Construct object.
$object=librdf_statement_get_object($statement);
$type=librdf_node_get_type($object);
$value='<'.$qname;
if ($type==LIBRDFUTIL_NODETYPE_RESOURCE)
$value.=' rdf:resource="'.htmlspecialchars(librdf_uri_to_string(librdf_node_get_uri($object))).'"/';
elseif ($type==LIBRDFUTIL_NODETYPE_BNODE)
$value.=' rdf:nodeID="'.htmlspecialchars(librdf_node_get_blank_identifier($object)).'"/';
elseif ($type==LIBRDFUTIL_NODETYPE_LITERAL) {
if (librdf_node_get_literal_value_language($object)!='')
$value.=' xml:lang="'.htmlspecialchars(librdf_node_get_literal_value_language($object)).'"';
# if (librdf_node_get_literal_value_datatype_uri($object)!='')
# $xml.=' rdf:datatype="'.htmlspecialchars(librdf_uri_to_string(librdf_node_get_literal_value_datatype_uri($object))).'"';
if (librdf_node_get_literal_value_is_wf_xml($object))
$value.=' rdf:parseType="Literal">'.librdf_node_get_literal_value($object).'</'.$qname;
else
$value.='>'.htmlspecialchars(librdf_node_get_literal_value($object)).'</'.$qname;
}
$value.='>';
# Add to subject/predicate group.
$spgroups[$subject][$qname][]=$value;
librdf_stream_next($stream);
}
}
# Serialise...
$xml='<?xml version="1.0" encoding="UTF-8"?>'."\n".'<rdf:RDF';
foreach (array_keys($prefixes) as $prefix)
$xml.="\n".' xmlns:'.$prefix.'="'.$prefixes[$prefix].'"';
$xml.=">\n";
foreach (array_keys($spgroups) as $spgroup) {
$xml.='<rdf:Description '.$spgroup.'>';
foreach ($spgroups[$spgroup] as $properties) {
$xml.="\n ".join("\n ",$properties);
}
$xml.="\n".'</rdf:Description>'."\n";
}
$xml.="</rdf:RDF>";
return $xml;
}
/**
* librdfutil_node_to_turtle_string: Generate Turtle syntax fragment for node.
* @node: a librdf_node
* @ns: (optional) PHP associative array with prefix=>namespace mappings for QNames.
* @options: (optional) PHP array with Turtle serialisation options:
* - multiline: Generate multiline literals with triple-quotes
* - noescape: Don't escape Unicode characters
*
**/
function librdfutil_node_to_turtle_string($node, $ns=array(), $options=array())
{
$type=librdf_node_get_type($node);
if ($type==LIBRDFUTIL_NODETYPE_RESOURCE) {
$uri=librdf_uri_to_string(librdf_node_get_uri($node));
if (!array_key_exists('noescape', $options) || !$options['noescape'])
$uri=preg_replace_callback('|[\x00-\x09\x0B-\x0C\x0E-\x1F\x7F-\xFF]|',
create_function('$M','return sprintf("\\u%04x",ord($M[0]));'),
utf8_decode($uri));
foreach (array_keys($ns) as $prefix) {
$pos=strpos($uri, $ns[$prefix]);
if ($pos!==false && $pos==0)
return $prefix.':'.substr($uri, strlen($ns[$prefix])).' ';
}
return '<'.$uri.'> ';
}
elseif ($type==LIBRDFUTIL_NODETYPE_BNODE) {
$id=librdf_node_get_blank_identifier($node);
if (!array_key_exists('noescape', $options) || !$options['noescape'])
$id=preg_replace_callback('|[\x00-\x09\x0B-\x0C\x0E-\x1F\x7F-\xFF]|',
create_function('$M','return sprintf("\\u%04x",ord($M[0]));'),
utf8_decode($id));
return '_:'.$id.' ';
} elseif ($type==LIBRDFUTIL_NODETYPE_LITERAL) {
$value=librdf_node_get_literal_value($node);
if (!array_key_exists('noescape', $options) || !$options['noescape'])
$value=preg_replace_callback('|[\x00-\x09\x0B-\x0C\x0E-\x1F\x7F-\xFF]|',
create_function('$M','return sprintf("\\u%04x",ord($M[0]));'),
utf8_decode($value));
$value=str_replace('"', '\"', $value);
$value='"'.$value.'"';
if (array_key_exists('multiline', $options) && $options['multiline']
&& strpos($value, "\n")!==false)
$value='""'.$value.'""';
else
$value=str_replace("\n", '\n', $value);
if (librdf_node_get_literal_value_language($node)!='')
$value.='@'.librdf_node_get_literal_value_language($node);
# if (librdf_node_get_literal_value_datatype_uri($node)!='')
# $value.='^^'.librdf_uri_to_string(librdf_node_get_literal_value_datatype_uri($node));
return $value.' ';
}
return '';
}
/**
* librdfutil_node_to_hash: Get a string hash (the MySQL ID) of a node object.
* @node: a librdf_node
*
**/
function librdfutil_node_to_hash($node) {
# Extract node information for relevant type and return hash.
if(librdf_node_get_type($node)==LIBRDFUTIL_NODETYPE_RESOURCE)
return librdfutil_strings_to_hash('R',
librdf_uri_to_string(librdf_node_get_uri($node)));
if(librdf_node_get_type($node)==LIBRDFUTIL_NODETYPE_BNODE)
return librdfutil_strings_to_hash('B',
librdf_node_get_blank_identifier($node));
if(librdf_node_get_type($node)==LIBRDFUTIL_NODETYPE_LITERAL) {
$dt='';#(librdf_node_get_literal_value_datatype_uri($node)!='')?librdf_uri_to_string(librdf_node_get_literal_value_datatype_uri($node)):'';
return librdfutil_strings_to_hash('L',
librdf_node_get_literal_value($node),
(librdf_node_get_literal_value_language($node)!='')?librdf_node_get_literal_value_language($node):'',
$dt);
}
return 0;
}
/**
* librdfutil_strings_to_hash: Get a string hash (the MySQL ID) of a node.
* @type: the type of node, "L", "R" or "B"
* @value: the principal value of the node (no quotes or delimiters)
* @language: literal language value or the empty string
* @datatype: literal datatype URI or the empty string
*
**/
function librdfutil_strings_to_hash($type, $value='', $language='', $datatype='') {
# Literal?
if ($type == 'L')
$value.='<'.$language.'>'.$datatype;
# Compute MD5 digest.
$md5=md5($type.$value);
# Convert to integer (string).
$digest='0';
for ($i=0; $i<8; $i++) {
$dec=hexdec(substr($md5, $i*2, 2));
$dec=bcmul($dec, bcpow(2, $i*8));
$digest=bcadd($digest, $dec);
}
# Return result.
return $digest;
}
# Use native functions for large integers if available.
if (!function_exists('bcadd')) {
function bcadd($a,$b) {
while (strlen($a)<strlen($b))
$a='0'.$a;
while (strlen($b)<strlen($a))
$b='0'.$b;
$s='';
$i=strlen($a);
$c='0';
while ($i--) {
$x=''.($c + substr($a, $i, 1) + substr($b, $i, 1));
if ($x>9) {
$c=$x[0];
$s=$x[1].$s;
} else {
$c='0';
$s=$x[0].$s;
}
}
if ($c)
$s=$c.$s;
return $s;
}
}
if (!function_exists('bcpow')) {
function bcpow($a, $b) {
$r=1;
while ($b--)
$r=bcmul($r, $a);
return $r;
}
}
if(!function_exists('bcmul')) {
function bcmul($a, $b) {
# Count digits for each number and the total
$n1=strlen($a);
$n2=strlen($b);
$nn=$n1+$n2;
# Put each in an array, $a1[0] is the right most digit of the first number, etc.
$a1=array();
for ($i=$n1-1; $i>=0; $i--)
$a1[]=intval(substr($a, $i, 1));
$a2=array();
for ($i=$n2-1; $i>=0; $i--)
$a2[]=intval(substr($b, $i, 1));
# Prepare empty string for result
$result='';
$carry=0;
# Calculations, loop through each digit of result
for ($i=0; $i<=$nn-2; $i++) {
$j1=$i;
if ($j1>$n1-1)
$j1=$n1-1;
$sum=$carry;
for ($j=$j1; $j>=0; $j--) {
# $j, $k are indices of each pair of digits
$k=$i-$j;
if ($k>=0 && $k<=$n2-1)
$sum+=$a1[$j]*$a2[$k];
}
# Add right-most digit to result, the rest carried
$digit=$sum%10;
$carry=($sum-$digit)/10;
$digit=$digit;
# Add new digit to the left
$result=$digit.$result;
}
# Last carry
if ($carry!=0)
$result=$carry.$result;
return $result;
}
}
?>