Update fromRDF to comply with recent changes to the spec.

This commit is contained in:
Dave Longley 2013-05-17 16:59:32 -04:00
parent 66bddc2ab9
commit 4d4334ea43
1 changed files with 116 additions and 127 deletions

View File

@ -1,7 +1,7 @@
<?php <?php
/** /**
* PHP implementation of the JSON-LD API. * PHP implementation of the JSON-LD API.
* Version: 0.0.32 * Version: 0.0.33
* *
* @author Dave Longley * @author Dave Longley
* *
@ -2502,153 +2502,147 @@ class JsonLdProcessor {
* @return array the JSON-LD output. * @return array the JSON-LD output.
*/ */
protected function _fromRDF($dataset, $options) { protected function _fromRDF($dataset, $options) {
// prepare graph map (maps graph name => subjects, lists) $default_graph = new stdClass();
$default_graph = (object)array( $graph_map = (object)array('@default' => $default_graph);
'subjects' => new stdClass(), 'listMap' => new stdClass());
$graphs = (object)array('@default' => $default_graph);
foreach($dataset as $graph_name => $triples) { foreach($dataset as $name => $graph) {
foreach($triples as $triple) { if(!property_exists($graph_map, $name)) {
$graph_map->{$name} = new stdClass();
}
if($name !== '@default' && !property_exists($default_graph, $name)) {
$default_graph->{$name} = (object)array('@id' => $name);
}
$node_map = $graph_map->{$name};
foreach($graph as $triple) {
// get subject, predicate, object // get subject, predicate, object
$s = $triple->subject->value; $s = $triple->subject->value;
$p = $triple->predicate->value; $p = $triple->predicate->value;
$o = $triple->object; $o = $triple->object;
// create a named graph entry as needed if(!property_exists($node_map, $s)) {
if(!property_exists($graphs, $graph_name)) { $node_map->{$s} = (object)array('@id' => $s);
$graph = $graphs->{$graph_name} = (object)array(
'subjects' => new stdClass(), 'listMap' => new stdClass());
} }
else { $node = $node_map->{$s};
$graph = $graphs->{$graph_name};
$object_is_id = ($o->type === 'IRI' || $o->type === 'blank node');
if($object_is_id && $o->value !== self::RDF_NIL &&
!property_exists($node_map, $o->value)) {
$node_map->{$o->value} = (object)array('@id' => $o->value);
} }
// handle element in @list if($p === self::RDF_TYPE && $object_is_id) {
if($p === self::RDF_FIRST) {
// create list entry as needed
$list_map = $graph->listMap;
if(!property_exists($list_map, $s)) {
$entry = $list_map->{$s} = new stdClass();
}
else {
$entry = $list_map->{$s};
}
// set object value
$entry->first = $this->_RDFToObject($o, $options['useNativeTypes']);
continue;
}
// handle other element in @list
if($p === self::RDF_REST) {
// set next in list
if($o->type === 'blank node') {
// create list entry as needed
$list_map = $graph->listMap;
if(!property_exists($list_map, $s)) {
$entry = $list_map->{$s} = new stdClass();
}
else {
$entry = $list_map->{$s};
}
$entry->rest = $o->value;
}
continue;
}
// add graph subject to the default graph as needed
if($graph_name !== '@default' &&
!property_exists($default_graph->subjects, $graph_name)) {
$default_graph->subjects->{$graph_name} = (object)array(
'@id' => $graph_name);
}
// add subject to graph as needed
$subjects = $graph->subjects;
if(!property_exists($subjects, $s)) {
$value = $subjects->{$s} = (object)array('@id' => $s);
}
// use existing subject value
else {
$value = $subjects->{$s};
}
// convert to @type unless options indicate to treat rdf:type as property
if($p === self::RDF_TYPE && !$options['useRdfType']) {
// add value of object as @type
self::addValue( self::addValue(
$value, '@type', $o->value, array('propertyIsArray' => true)); $node, '@type', $o->value, array('propertyIsArray' => true));
continue;
}
if($object_is_id &&
$o->value === self::RDF_NIL && $p !== self::RDF_REST) {
// empty list detected
$value = (object)array('@list' => array());
} }
else { else {
// add property to value as needed $value = self::_RDFToObject($o, $options['useNativeTypes']);
$object = $this->_RDFToObject($o, $options['useNativeTypes']); }
self::addValue($value, $p, $object, array('propertyIsArray' => true)); self::addValue($node, $p, $value, array('propertyIsArray' => true));
// a bnode might be the beginning of a list, so add it to the list map // object may be the head of an RDF list but we can't know easily
if($o->type === 'blank node') { // until all triples are read
$id = $object->{'@id'}; if($o->type === 'blank node' &&
$list_map = $graph->listMap; !($p === self::RDF_FIRST || $p === self::RDF_REST)) {
if(!property_exists($list_map, $id)) { $object = $node_map->{$o->value};
$entry = $list_map->{$id} = new stdClass(); if(!property_exists($object, 'listHeadFor')) {
} $object->listHeadFor = $value;
else { }
$entry = $list_map->{$id}; // can't be a list head if referenced more than once
} else {
$entry->head = $object; $object->listHeadFor = null;
} }
} }
} }
} }
// build @lists // convert linked lists to @list arrays
foreach($graphs as $graph_name => $graph) { foreach($graph_map as $name => $graph_object) {
// find list head foreach($graph_object as $subject => $node) {
$list_map = $graph->listMap; // if subject not in graph_object, it has been removed as it was
foreach($list_map as $subject => $entry) { // part of an RDF list, continue
// head found, build lists if(!property_exists($graph_object, $subject)) {
if(property_exists($entry, 'head') && continue;
property_exists($entry, 'first')) { }
// replace bnode @id with @list // if value is not an object, it can't be a list head, continue
$value = $entry->head; $value = (property_exists($node, 'listHeadFor') ?
unset($value->{'@id'}); $node->listHeadFor : null);
$list = array($entry->first); if(!is_object($value)) {
while(property_exists($entry, 'rest')) { continue;
$rest = $entry->rest; }
$entry = $list_map->{$rest};
if(!property_exists($entry, 'first')) { $list = array();
throw new JsonLdException( $eliminated_nodes = new stdClass();
'Invalid RDF list entry.', while($subject !== self::RDF_NIL && $list !== null) {
'jsonld.RdfError', array('bnode' => $rest)); // ensure node is a valid list node; node must:
} // 1. Be a blank node
$list[] = $entry->first; // 2. Have no keys other than: @id, listHeadFor, rdf:first, rdf:rest.
// 3. Have an array for rdf:first that has 1 item.
// 4. Have an array for rdf:rest that has 1 object with @id.
// 5. Not already be in a list (it is in the eliminated nodes map).
$node_key_count = (is_object($node) ?
count(array_keys((array)$node)) : 0);
if(!(is_object($node) && strpos($node->{'@id'}, '_:') === 0 &&
($node_key_count === 3 || ($node_key_count === 4 &&
property_exists($node, 'listHeadFor'))) &&
is_array($node->{self::RDF_FIRST}) &&
count($node->{self::RDF_FIRST}) === 1 &&
is_array($node->{self::RDF_REST}) &&
count($node->{self::RDF_REST}) === 1 &&
is_object($node->{self::RDF_REST}[0]) &&
property_exists($node->{self::RDF_REST}[0], '@id') &&
!property_exists($eliminated_nodes, $subject))) {
$list = null;
break;
} }
$value->{'@list'} = $list;
$list[] = $node->{self::RDF_FIRST}[0];
$eliminated_nodes->{$node->{'@id'}} = true;
$subject = $node->{self::RDF_REST}[0]->{'@id'};
$node = (property_exists($graph_object, $subject) ?
$graph_object->{$subject} : null);
}
// bad list detected, skip it
if($list === null) {
continue;
}
unset($value->{'@id'});
$value->{'@list'} = $list;
foreach($eliminated_nodes as $id => $b) {
unset($graph_object->{$id});
} }
} }
} }
// build default graph in subject @id order $result = array();
$output = array(); $subjects = array_keys((array)$default_graph);
$subjects = $default_graph->subjects; sort($subjects);
$ids = array_keys((array)$subjects); foreach($subjects as $subject) {
sort($ids); $node = $default_graph->{$subject};
foreach($ids as $i => $id) { if(property_exists($graph_map, $subject)) {
// add subject to default graph $node->{'@graph'} = array();
$subject = $subjects->{$id}; $graph_object = $graph_map->{$subject};
$output[] = $subject; $subjects_ = array_keys((array)$graph_object);
sort($subjects_);
// output named graph in subject @id order foreach($subjects_ as $subject_) {
if(property_exists($graphs, $id)) { $node_ = $graph_object->{$subject_};
$graph = array(); unset($node_->listHeadFor);
$subjects_ = $graphs->{$id}->subjects; $node->{'@graph'}[] = $node_;
$ids_ = array_keys((array)$subjects_);
sort($ids_);
foreach($ids_ as $i_ => $id_) {
$graph[] = $subjects_->{$id_};
} }
$subject->{'@graph'} = $graph;
} }
unset($node->listHeadFor);
$result[] = $node;
} }
return $output;
return $result;
} }
/** /**
@ -3081,11 +3075,6 @@ class JsonLdProcessor {
* @return stdClass the JSON-LD object. * @return stdClass the JSON-LD object.
*/ */
protected function _RDFToObject($o, $use_native_types) { protected function _RDFToObject($o, $use_native_types) {
// convert empty list
if($o->type === 'IRI' && $o->value === self::RDF_NIL) {
return (object)array('@list' => array());
}
// convert IRI/blank node object to JSON-LD // convert IRI/blank node object to JSON-LD
if($o->type === 'IRI' || $o->type === 'blank node') { if($o->type === 'IRI' || $o->type === 'blank node') {
return (object)array('@id' => $o->value); return (object)array('@id' => $o->value);