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 implementation of the JSON-LD API.
* Version: 0.0.15
* Version: 0.0.16
*
* @author Dave Longley
*
@ -1698,29 +1698,11 @@ class JsonLdProcessor {
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
$keys = array_keys((array)$element);
sort($keys);
$rval = new stdClass();
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};
// compact @id and @type(s)
@ -1771,7 +1753,7 @@ class JsonLdProcessor {
if(count($expanded_value) === 0) {
$item_active_property = $this->_compactIri(
$active_ctx, $expanded_property, $expanded_value,
array('vocab' => true), $element);
array('vocab' => true));
self::addValue(
$rval, $item_active_property, array(),
array('propertyIsArray' => true));
@ -1782,21 +1764,10 @@ class JsonLdProcessor {
// compact property and get container type
$item_active_property = $this->_compactIri(
$active_ctx, $expanded_property, $expanded_item,
array('vocab' => true), $element);
array('vocab' => true));
$container = self::getContextValue(
$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
$is_list = self::_isList($expanded_item);
$list = null;
@ -1957,20 +1928,13 @@ class JsonLdProcessor {
$mapping = null;
}
// expand key using property generator
if($mapping && $mapping->propertyGenerator) {
$expanded_property = $mapping->{'@id'};
}
// expand key to IRI
else {
$expanded_property = $this->_expandIri(
$active_ctx, $key, array('vocab' => true));
}
$expanded_property = $this->_expandIri(
$active_ctx, $key, array('vocab' => true));
// drop non-absolute IRI keys that aren't keywords
if($expanded_property === null ||
!(is_array($expanded_property) ||
self::_isAbsoluteIri($expanded_property) ||
!(self::_isAbsoluteIri($expanded_property) ||
self::_isKeyword($expanded_property))) {
continue;
}
@ -2088,26 +2052,14 @@ class JsonLdProcessor {
'@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
else {
// use an array except for certain keywords
$use_array = (!in_array(
$expanded_property, array(
'@index', '@id', '@type', '@value', '@language')));
self::addValue(
$rval, $expanded_property, $expanded_value,
array('propertyIsArray' => $use_array));
}
// use an array except for certain keywords
$use_array = (!in_array(
$expanded_property, array(
'@index', '@id', '@type', '@value', '@language')));
self::addValue(
$rval, $expanded_property, $expanded_value,
array('propertyIsArray' => $use_array));
}
// get property count on expanded output
@ -3917,7 +3869,6 @@ class JsonLdProcessor {
* @param active_ctx the active context.
* @param iri the IRI 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 type_or_language either '@type' or '@language'.
* @param type_or_language_value the preferred value for '@type' or
@ -3926,7 +3877,7 @@ class JsonLdProcessor {
* @return mixed the preferred term.
*/
protected function _selectTerm(
$active_ctx, $iri, $value, $parent, $containers,
$active_ctx, $iri, $value, $containers,
$type_or_language, $type_or_language_value) {
$containers[] = '@none';
if($type_or_language_value === null) {
@ -3969,33 +3920,14 @@ class JsonLdProcessor {
$type_or_language_value_map =
$container_map->{$container}->{$type_or_language};
foreach($options as $option) {
if($term !== null) {
break;
}
// if type/language option not available in the map, continue
if(!property_exists($type_or_language_value_map, $option)) {
continue;
}
$term_info = $type_or_language_value_map->{$option};
// see if a property generator matches
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;
}
// select term
$term = $type_or_language_value_map->{$option};
break;
}
}
return $term;
@ -4010,12 +3942,11 @@ class JsonLdProcessor {
* @param mixed $value the value to check or null.
* @param assoc $relative_to options for how to compact IRIs:
* 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.
*/
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
if($iri === null) {
return $iri;
@ -4127,7 +4058,7 @@ class JsonLdProcessor {
// do term selection
$term = $this->_selectTerm(
$active_ctx, $iri, $value, $parent,
$active_ctx, $iri, $value,
$containers, $type_or_language, $type_or_language_value);
if($term !== null) {
return $term;
@ -4142,7 +4073,7 @@ class JsonLdProcessor {
continue;
}
// skip entries with @ids that are not partial matches
if($definition === null || $definition->propertyGenerator ||
if($definition === null ||
$definition->{'@id'} === $iri ||
strpos($iri, $definition->{'@id'}) !== 0) {
continue;
@ -4290,76 +4221,6 @@ class JsonLdProcessor {
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.
*
@ -4436,8 +4297,7 @@ class JsonLdProcessor {
}
// define/redefine term to expanded IRI/keyword
$active_ctx->mappings->{$term} = (object)array(
'@id' => $id, 'propertyGenerator' => false);
$active_ctx->mappings->{$term} = (object)array('@id' => $id);
$defined->{$term} = true;
return;
}
@ -4451,44 +4311,10 @@ class JsonLdProcessor {
// create new mapping
$mapping = new stdClass();
$mapping->propertyGenerator = false;
if(property_exists($value, '@id')) {
$id = $value->{'@id'};
// handle property generator
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)) {
if(!is_string($id)) {
throw new JsonLdException(
'Invalid JSON-LD syntax; @context @id value must be an array ' .
'of strings or a string.',
@ -4626,15 +4452,7 @@ class JsonLdProcessor {
if(isset($relative_to['vocab']) && $relative_to['vocab']) {
if(property_exists($active_ctx->mappings, $value)) {
// term dependency cannot be a property generator
$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
if($mapping === null) {
@ -4642,9 +4460,7 @@ class JsonLdProcessor {
}
// 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);
}
// use mapping if prefix is defined and not a property generator
// use mapping if prefix is defined
if(property_exists($active_ctx->mappings, $prefix)) {
$mapping = $active_ctx->mappings->{$prefix};
if($mapping && !$mapping->propertyGenerator) {
$rval = $active_ctx->mappings->{$prefix}->{'@id'} . $suffix;
if($mapping) {
$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 string $term the term to add.
@ -5016,16 +4832,7 @@ class JsonLdProcessor {
*/
function _addPreferredTerm($mapping, $term, $entry, $type_or_language_value) {
if(!property_exists($entry, $type_or_language_value)) {
$entry->{$type_or_language_value} = (object)array(
'term' => null, 'propertyGenerators' => array());
}
$e = $entry->{$type_or_language_value};
if($mapping->propertyGenerator) {
$e->propertyGenerators[] = $term;
}
else if($e->term === null) {
$e->term = $term;
$entry->{$type_or_language_value} = $term;
}
}