Remove property generator support.

This commit is contained in:
Dave Longley 2013-03-06 14:34:03 -05:00
parent e410888508
commit b0c1d0cfe8
1 changed files with 28 additions and 221 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.15 * Version: 0.0.16
* *
* @author Dave Longley * @author Dave Longley
* *
@ -1698,29 +1698,11 @@ class JsonLdProcessor {
return $this->_compactValue($active_ctx, $active_property, $element); return $this->_compactValue($active_ctx, $active_property, $element);
} }
// shallow copy element and arrays so keys and values can be removed
// during property generator compaction
$shallow = new stdClass();
foreach($element as $expanded_property => $expanded_value) {
if(is_array($element->{$expanded_property})) {
$shallow->{$expanded_property} = $element->{$expanded_property};
}
else {
$shallow->{$expanded_property} = $element->{$expanded_property};
}
}
$element = $shallow;
// process element keys in order // process element keys in order
$keys = array_keys((array)$element); $keys = array_keys((array)$element);
sort($keys); sort($keys);
$rval = new stdClass(); $rval = new stdClass();
foreach($keys as $expanded_property) { foreach($keys as $expanded_property) {
// skip key if removed during property generator duplicate handling
if(!property_exists($element, $expanded_property)) {
continue;
}
$expanded_value = $element->{$expanded_property}; $expanded_value = $element->{$expanded_property};
// compact @id and @type(s) // compact @id and @type(s)
@ -1771,7 +1753,7 @@ class JsonLdProcessor {
if(count($expanded_value) === 0) { if(count($expanded_value) === 0) {
$item_active_property = $this->_compactIri( $item_active_property = $this->_compactIri(
$active_ctx, $expanded_property, $expanded_value, $active_ctx, $expanded_property, $expanded_value,
array('vocab' => true), $element); array('vocab' => true));
self::addValue( self::addValue(
$rval, $item_active_property, array(), $rval, $item_active_property, array(),
array('propertyIsArray' => true)); array('propertyIsArray' => true));
@ -1782,21 +1764,10 @@ class JsonLdProcessor {
// compact property and get container type // compact property and get container type
$item_active_property = $this->_compactIri( $item_active_property = $this->_compactIri(
$active_ctx, $expanded_property, $expanded_item, $active_ctx, $expanded_property, $expanded_item,
array('vocab' => true), $element); array('vocab' => true));
$container = self::getContextValue( $container = self::getContextValue(
$active_ctx, $item_active_property, '@container'); $active_ctx, $item_active_property, '@container');
// remove any duplicates that were (presumably) generated by a
// property generator
if(property_exists($active_ctx->mappings, $item_active_property)) {
$mapping = $active_ctx->mappings->{$item_active_property};
if($mapping && $mapping->propertyGenerator) {
$this->_findPropertyGeneratorDuplicates(
$active_ctx, $element, $expanded_property, $expanded_item,
$item_active_property, true);
}
}
// get @list value if appropriate // get @list value if appropriate
$is_list = self::_isList($expanded_item); $is_list = self::_isList($expanded_item);
$list = null; $list = null;
@ -1957,20 +1928,13 @@ class JsonLdProcessor {
$mapping = null; $mapping = null;
} }
// expand key using property generator
if($mapping && $mapping->propertyGenerator) {
$expanded_property = $mapping->{'@id'};
}
// expand key to IRI // expand key to IRI
else { $expanded_property = $this->_expandIri(
$expanded_property = $this->_expandIri( $active_ctx, $key, array('vocab' => true));
$active_ctx, $key, array('vocab' => true));
}
// drop non-absolute IRI keys that aren't keywords // drop non-absolute IRI keys that aren't keywords
if($expanded_property === null || if($expanded_property === null ||
!(is_array($expanded_property) || !(self::_isAbsoluteIri($expanded_property) ||
self::_isAbsoluteIri($expanded_property) ||
self::_isKeyword($expanded_property))) { self::_isKeyword($expanded_property))) {
continue; continue;
} }
@ -2088,26 +2052,14 @@ class JsonLdProcessor {
'@list' => self::arrayify($expanded_value)); '@list' => self::arrayify($expanded_value));
} }
// add copy of value for each property from property generator
if(is_array($expanded_property)) {
$expanded_value = $this->_labelBlankNodes(
$active_ctx->namer, $expanded_value);
foreach($expanded_property as $iri) {
self::addValue(
$rval, $iri, self::copy($expanded_value),
array('propertyIsArray' => true));
}
}
// add value for property // add value for property
else { // use an array except for certain keywords
// use an array except for certain keywords $use_array = (!in_array(
$use_array = (!in_array( $expanded_property, array(
$expanded_property, array( '@index', '@id', '@type', '@value', '@language')));
'@index', '@id', '@type', '@value', '@language'))); self::addValue(
self::addValue( $rval, $expanded_property, $expanded_value,
$rval, $expanded_property, $expanded_value, array('propertyIsArray' => $use_array));
array('propertyIsArray' => $use_array));
}
} }
// get property count on expanded output // get property count on expanded output
@ -3917,7 +3869,6 @@ class JsonLdProcessor {
* @param active_ctx the active context. * @param active_ctx the active context.
* @param iri the IRI to pick the term for. * @param iri the IRI to pick the term for.
* @param value the value to pick the term for. * @param value the value to pick the term for.
* @param parent the parent of the value (required for property generators).
* @param containers the preferred containers. * @param containers the preferred containers.
* @param type_or_language either '@type' or '@language'. * @param type_or_language either '@type' or '@language'.
* @param type_or_language_value the preferred value for '@type' or * @param type_or_language_value the preferred value for '@type' or
@ -3926,7 +3877,7 @@ class JsonLdProcessor {
* @return mixed the preferred term. * @return mixed the preferred term.
*/ */
protected function _selectTerm( protected function _selectTerm(
$active_ctx, $iri, $value, $parent, $containers, $active_ctx, $iri, $value, $containers,
$type_or_language, $type_or_language_value) { $type_or_language, $type_or_language_value) {
$containers[] = '@none'; $containers[] = '@none';
if($type_or_language_value === null) { if($type_or_language_value === null) {
@ -3969,33 +3920,14 @@ class JsonLdProcessor {
$type_or_language_value_map = $type_or_language_value_map =
$container_map->{$container}->{$type_or_language}; $container_map->{$container}->{$type_or_language};
foreach($options as $option) { foreach($options as $option) {
if($term !== null) {
break;
}
// if type/language option not available in the map, continue // if type/language option not available in the map, continue
if(!property_exists($type_or_language_value_map, $option)) { if(!property_exists($type_or_language_value_map, $option)) {
continue; continue;
} }
$term_info = $type_or_language_value_map->{$option}; // select term
$term = $type_or_language_value_map->{$option};
// see if a property generator matches break;
if(is_object($parent)) {
foreach($term_info->propertyGenerators as $property_generator) {
$match = $this->_findPropertyGeneratorDuplicates(
$active_ctx, $parent, $iri, $value, $property_generator, false);
if($match) {
$term = $property_generator;
break;
}
}
}
// no matching property generator, use a simple term instead
if($term === null) {
$term = $term_info->term;
}
} }
} }
return $term; return $term;
@ -4010,12 +3942,11 @@ class JsonLdProcessor {
* @param mixed $value the value to check or null. * @param mixed $value the value to check or null.
* @param assoc $relative_to options for how to compact IRIs: * @param assoc $relative_to options for how to compact IRIs:
* vocab: true to split after @vocab, false not to. * vocab: true to split after @vocab, false not to.
* @param mixed $parent the parent element for the value.
* *
* @return string the compacted term, prefix, keyword alias, or original IRI. * @return string the compacted term, prefix, keyword alias, or original IRI.
*/ */
protected function _compactIri( protected function _compactIri(
$active_ctx, $iri, $value=null, $relative_to=array(), $parent=null) { $active_ctx, $iri, $value=null, $relative_to=array()) {
// can't compact null // can't compact null
if($iri === null) { if($iri === null) {
return $iri; return $iri;
@ -4127,7 +4058,7 @@ class JsonLdProcessor {
// do term selection // do term selection
$term = $this->_selectTerm( $term = $this->_selectTerm(
$active_ctx, $iri, $value, $parent, $active_ctx, $iri, $value,
$containers, $type_or_language, $type_or_language_value); $containers, $type_or_language, $type_or_language_value);
if($term !== null) { if($term !== null) {
return $term; return $term;
@ -4142,7 +4073,7 @@ class JsonLdProcessor {
continue; continue;
} }
// skip entries with @ids that are not partial matches // skip entries with @ids that are not partial matches
if($definition === null || $definition->propertyGenerator || if($definition === null ||
$definition->{'@id'} === $iri || $definition->{'@id'} === $iri ||
strpos($iri, $definition->{'@id'}) !== 0) { strpos($iri, $definition->{'@id'}) !== 0) {
continue; continue;
@ -4290,76 +4221,6 @@ class JsonLdProcessor {
return $rval; return $rval;
} }
/**
* Finds and, if specified, removes any duplicate values that were
* presumably generated by a property generator in the given element.
*
* @param stdClass $active_ctx the active context.
* @param stdClass $element the element to remove duplicates from.
* @param string $expanded_property the property to map to a property
* generator.
* @param mixed $value the value to compare against when duplicate checking.
* @param string $active_property the property generator term.
* @param bool $remove true to remove the duplicates found, false not to.
*
* @return bool true if duplicates were found for every IRI.
*/
protected function _findPropertyGeneratorDuplicates(
$active_ctx, $element, $expanded_property, $value, $active_property,
$remove) {
$rval = true;
// get property generator IRIs
$iris = $active_ctx->mappings->{$active_property}->{'@id'};
// for each IRI that isn't 'expandedProperty', remove a single duplicate
// from element, if found
foreach($iris as $iri) {
if($rval === false) {
break;
}
if($iri === $expanded_property) {
continue;
}
$rval = false;
if(!property_exists($element, $iri)) {
break;
}
$length = count($element->{$iri});
// handle empty array case
if(is_array($value) && count($value) === 0) {
$rval = true;
if($remove) {
unset($element->{$iri});
}
continue;
}
// handle other cases
for($pi = 0; $pi < $length; ++$pi) {
if(self::compareValues($element->{$iri}[$pi], $value)) {
// duplicate found
$rval = true;
if($remove) {
// remove it in place
array_splice($element->{$iri}, $pi, 1);
if(count($element->{$iri}) === 0) {
unset($element->{$iri});
}
}
break;
}
}
}
return $rval;
}
/** /**
* Creates a term definition during context processing. * Creates a term definition during context processing.
* *
@ -4436,8 +4297,7 @@ class JsonLdProcessor {
} }
// define/redefine term to expanded IRI/keyword // define/redefine term to expanded IRI/keyword
$active_ctx->mappings->{$term} = (object)array( $active_ctx->mappings->{$term} = (object)array('@id' => $id);
'@id' => $id, 'propertyGenerator' => false);
$defined->{$term} = true; $defined->{$term} = true;
return; return;
} }
@ -4451,44 +4311,10 @@ class JsonLdProcessor {
// create new mapping // create new mapping
$mapping = new stdClass(); $mapping = new stdClass();
$mapping->propertyGenerator = false;
if(property_exists($value, '@id')) { if(property_exists($value, '@id')) {
$id = $value->{'@id'}; $id = $value->{'@id'};
// handle property generator if(!is_string($id)) {
if(is_array($id)) {
if($active_ctx->namer === null) {
throw new JsonLdException(
'Incompatible JSON-LD options; a property generator was found ' .
'in the @context, but blank node renaming has been disabled; ' .
'it must be enabled to use property generators.',
'jsonld.OptionsError', array('context' => $local_ctx));
}
$property_generator = array();
$ids = $id;
foreach($ids as $id) {
// expand @id
if(is_string($id)) {
$id = $this->_expandIri(
$active_ctx, $id, array('vocab' => true, 'base' => true),
$local_ctx, $defined);
}
if(!is_string($id) || self::_isKeyword($id)) {
throw new JsonLdException(
'Invalid JSON-LD syntax; property generators must consist of ' .
'an @id array containing only strings and no string can be ' .
'"@type".',
'jsonld.SyntaxError', array('context' => $local_ctx));
}
$property_generator[] = $id;
}
// add sorted property generator as @id in mapping
sort($property_generator);
$mapping->{'@id'} = $property_generator;
$mapping->propertyGenerator = true;
}
else if(!is_string($id)) {
throw new JsonLdException( throw new JsonLdException(
'Invalid JSON-LD syntax; @context @id value must be an array ' . 'Invalid JSON-LD syntax; @context @id value must be an array ' .
'of strings or a string.', 'of strings or a string.',
@ -4626,15 +4452,7 @@ class JsonLdProcessor {
if(isset($relative_to['vocab']) && $relative_to['vocab']) { if(isset($relative_to['vocab']) && $relative_to['vocab']) {
if(property_exists($active_ctx->mappings, $value)) { if(property_exists($active_ctx->mappings, $value)) {
// term dependency cannot be a property generator
$mapping = $active_ctx->mappings->{$value}; $mapping = $active_ctx->mappings->{$value};
if($local_ctx !== null && $mapping && $mapping->propertyGenerator) {
throw new JsonLdException(
'Invalid JSON-LD syntax; a term definition cannot have a property ' .
'generator as a dependency.',
'jsonld.SyntaxError',
array('context' => $local_ctx, 'value' => $value));
}
// value is explicitly ignored with a null mapping // value is explicitly ignored with a null mapping
if($mapping === null) { if($mapping === null) {
@ -4642,9 +4460,7 @@ class JsonLdProcessor {
} }
// value is a term // value is a term
if(!$mapping->propertyGenerator) { $rval = $mapping->{'@id'};
$rval = $mapping->{'@id'};
}
} }
} }
@ -4664,11 +4480,11 @@ class JsonLdProcessor {
$active_ctx, $local_ctx, $prefix, $defined); $active_ctx, $local_ctx, $prefix, $defined);
} }
// use mapping if prefix is defined and not a property generator // use mapping if prefix is defined
if(property_exists($active_ctx->mappings, $prefix)) { if(property_exists($active_ctx->mappings, $prefix)) {
$mapping = $active_ctx->mappings->{$prefix}; $mapping = $active_ctx->mappings->{$prefix};
if($mapping && !$mapping->propertyGenerator) { if($mapping) {
$rval = $active_ctx->mappings->{$prefix}->{'@id'} . $suffix; $rval = $mapping->{'@id'} . $suffix;
} }
} }
} }
@ -5006,7 +4822,7 @@ class JsonLdProcessor {
} }
/** /**
* Adds or updates the term or property generator for the given entry. * Adds the term for the given entry if not already added.
* *
* @param stdClass $mapping the term mapping. * @param stdClass $mapping the term mapping.
* @param string $term the term to add. * @param string $term the term to add.
@ -5016,16 +4832,7 @@ class JsonLdProcessor {
*/ */
function _addPreferredTerm($mapping, $term, $entry, $type_or_language_value) { function _addPreferredTerm($mapping, $term, $entry, $type_or_language_value) {
if(!property_exists($entry, $type_or_language_value)) { if(!property_exists($entry, $type_or_language_value)) {
$entry->{$type_or_language_value} = (object)array( $entry->{$type_or_language_value} = $term;
'term' => null, 'propertyGenerators' => array());
}
$e = $entry->{$type_or_language_value};
if($mapping->propertyGenerator) {
$e->propertyGenerators[] = $term;
}
else if($e->term === null) {
$e->term = $term;
} }
} }