forked from friendica/php-json-ld
Remove property generator support.
This commit is contained in:
parent
e410888508
commit
b0c1d0cfe8
227
jsonld.php
227
jsonld.php
|
@ -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));
|
||||
}
|
||||
|
||||
// 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,18 +2052,7 @@ 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(
|
||||
|
@ -2108,7 +2061,6 @@ class JsonLdProcessor {
|
|||
$rval, $expanded_property, $expanded_value,
|
||||
array('propertyIsArray' => $use_array));
|
||||
}
|
||||
}
|
||||
|
||||
// get property count on expanded output
|
||||
$keys = array_keys((array)$rval);
|
||||
|
@ -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,35 +3920,16 @@ 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;
|
||||
// select term
|
||||
$term = $type_or_language_value_map->{$option};
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no matching property generator, use a simple term instead
|
||||
if($term === null) {
|
||||
$term = $term_info->term;
|
||||
}
|
||||
}
|
||||
}
|
||||
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,11 +4460,9 @@ class JsonLdProcessor {
|
|||
}
|
||||
|
||||
// value is a term
|
||||
if(!$mapping->propertyGenerator) {
|
||||
$rval = $mapping->{'@id'};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($rval === null) {
|
||||
// split value into prefix:suffix
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue