Support more error conditions in expand.

This commit is contained in:
Dave Longley 2013-09-13 16:42:10 -04:00
parent 12a9ccc9e8
commit 60c335a6e9
1 changed files with 79 additions and 60 deletions

View File

@ -2079,6 +2079,9 @@ class JsonLdProcessor {
// recursively expand array // recursively expand array
if(is_array($element)) { if(is_array($element)) {
$rval = array(); $rval = array();
$container = self::getContextValue(
$active_ctx, $active_property, '@container');
$inside_list = $inside_list || $container === '@list';
foreach($element as $e) { foreach($element as $e) {
// expand element // expand element
$e = $this->_expand( $e = $this->_expand(
@ -2087,10 +2090,10 @@ class JsonLdProcessor {
// lists of lists are illegal // lists of lists are illegal
throw new JsonLdException( throw new JsonLdException(
'Invalid JSON-LD syntax; lists of lists are not permitted.', 'Invalid JSON-LD syntax; lists of lists are not permitted.',
'jsonld.SyntaxError'); 'jsonld.SyntaxError', 'list of lists');
} }
// drop null values // drop null values
else if($e !== null) { if($e !== null) {
if(is_array($e)) { if(is_array($e)) {
$rval = array_merge($rval, $e); $rval = array_merge($rval, $e);
} }
@ -2103,7 +2106,7 @@ class JsonLdProcessor {
} }
if(!is_object($element)) { if(!is_object($element)) {
// drop top-level scalars that are not in lists // drop free-floating scalars that are not in lists
if(!$inside_list && if(!$inside_list &&
($active_property === null || ($active_property === null ||
$this->_expandIri($active_ctx, $active_property, $this->_expandIri($active_ctx, $active_property,
@ -2137,14 +2140,6 @@ class JsonLdProcessor {
continue; continue;
} }
// get term definition for key
if(property_exists($active_ctx->mappings, $key)) {
$mapping = $active_ctx->mappings->{$key};
}
else {
$mapping = null;
}
// expand key to IRI // expand key to IRI
$expanded_property = $this->_expandIri( $expanded_property = $this->_expandIri(
$active_ctx, $key, array('vocab' => true)); $active_ctx, $key, array('vocab' => true));
@ -2156,19 +2151,35 @@ class JsonLdProcessor {
continue; continue;
} }
if(self::_isKeyword($expanded_property) && if(self::_isKeyword($expanded_property)) {
$expanded_active_property === '@reverse') { if($expanded_active_property === '@reverse') {
throw new JsonLdException( throw new JsonLdException(
'Invalid JSON-LD syntax; a keyword cannot be used as a @reverse ' . 'Invalid JSON-LD syntax; a keyword cannot be used as a @reverse ' .
'property.', 'property.', 'jsonld.SyntaxError', 'invalid reverse property map',
'jsonld.SyntaxError', array('value' => $value)); array('value' => $value));
}
if(property_exists($rval, $expanded_property)) {
throw new JsonLdException(
'Invalid JSON-LD syntax; colliding keywords detected.',
'jsonld.SyntaxError', 'colliding keywords',
array('keyword' => $expanded_property));
}
} }
// syntax error if @id is not a string // syntax error if @id is not a string
if($expanded_property === '@id' && !is_string($value)) { if($expanded_property === '@id' && !is_string($value)) {
throw new JsonLdException( if(!isset($options['isFrame']) && !$options['isFrame']) {
throw new JsonLdException(
'Invalid JSON-LD syntax; "@id" value must a string.', 'Invalid JSON-LD syntax; "@id" value must a string.',
'jsonld.SyntaxError', array('value' => $value)); 'jsonld.SyntaxError', 'invalid @id value',
array('value' => $value));
}
if(!is_object($value)) {
throw new JsonLdException(
'Invalid JSON-LD syntax; "@id" value must a string or an object.',
'jsonld.SyntaxError', 'invalid @id value',
array('value' => $value));
}
} }
// validate @type value // validate @type value
@ -2180,9 +2191,9 @@ class JsonLdProcessor {
if($expanded_property === '@graph' && if($expanded_property === '@graph' &&
!(is_object($value) || is_array($value))) { !(is_object($value) || is_array($value))) {
throw new JsonLdException( throw new JsonLdException(
'Invalid JSON-LD syntax; "@value" value must not be an ' . 'Invalid JSON-LD syntax; "@graph" value must not be an ' .
'object or an array.', 'object or an array.', 'jsonld.SyntaxError',
'jsonld.SyntaxError', array('value' => $value)); 'invalid @graph value', array('value' => $value));
} }
// @value must not be an object or an array // @value must not be an object or an array
@ -2190,15 +2201,18 @@ class JsonLdProcessor {
(is_object($value) || is_array($value))) { (is_object($value) || is_array($value))) {
throw new JsonLdException( throw new JsonLdException(
'Invalid JSON-LD syntax; "@value" value must not be an ' . 'Invalid JSON-LD syntax; "@value" value must not be an ' .
'object or an array.', 'object or an array.', 'jsonld.SyntaxError',
'jsonld.SyntaxError', array('value' => $value)); 'invalid value object value', array('value' => $value));
} }
// @language must be a string // @language must be a string
if($expanded_property === '@language' && !is_string($value)) { if($expanded_property === '@language') {
throw new JsonLdException( if(!is_string($value)) {
'Invalid JSON-LD syntax; "@language" value must not be a string.', throw new JsonLdException(
'jsonld.SyntaxError', array('value' => $value)); 'Invalid JSON-LD syntax; "@language" value must not be a string.',
'jsonld.SyntaxError', 'invalid language-tagged string',
array('value' => $value));
}
// ensure language value is lowercase // ensure language value is lowercase
$value = strtolower($value); $value = strtolower($value);
} }
@ -2208,7 +2222,8 @@ class JsonLdProcessor {
if(!is_string($value)) { if(!is_string($value)) {
throw new JsonLdException( throw new JsonLdException(
'Invalid JSON-LD syntax; "@index" value must be a string.', 'Invalid JSON-LD syntax; "@index" value must be a string.',
'jsonld.SyntaxError', array('value' => $value)); 'jsonld.SyntaxError', 'invalid @index value',
array('value' => $value));
} }
} }
@ -2217,7 +2232,8 @@ class JsonLdProcessor {
if(!is_object($value)) { if(!is_object($value)) {
throw new JsonLdException( throw new JsonLdException(
'Invalid JSON-LD syntax; "@reverse" value must be an object.', 'Invalid JSON-LD syntax; "@reverse" value must be an object.',
'jsonld.SyntaxError', array('value' => $value)); 'jsonld.SyntaxError', 'invalid @reverse value',
array('value' => $value));
} }
$expanded_value = $this->_expand( $expanded_value = $this->_expand(
@ -2253,8 +2269,8 @@ class JsonLdProcessor {
if(self::_isValue($item) || self::_isList($item)) { if(self::_isValue($item) || self::_isList($item)) {
throw new JsonLdException( throw new JsonLdException(
'Invalid JSON-LD syntax; "@reverse" value must not be a ' + 'Invalid JSON-LD syntax; "@reverse" value must not be a ' +
'@value or an @list.', '@value or an @list.', 'jsonld.SyntaxError',
'jsonld.SyntaxError', 'invalid reverse property value',
array('value' => $expanded_value)); array('value' => $expanded_value));
} }
self::addValue( self::addValue(
@ -2290,7 +2306,7 @@ class JsonLdProcessor {
} }
} }
else { else {
// recurse into @list or @set keeping the active property // recurse into @list or @set
$is_list = ($expanded_property === '@list'); $is_list = ($expanded_property === '@list');
if($is_list || $expanded_property === '@set') { if($is_list || $expanded_property === '@set') {
$next_active_property = $active_property; $next_active_property = $active_property;
@ -2302,7 +2318,7 @@ class JsonLdProcessor {
if($is_list && self::_isList($expanded_value)) { if($is_list && self::_isList($expanded_value)) {
throw new JsonLdException( throw new JsonLdException(
'Invalid JSON-LD syntax; lists of lists are not permitted.', 'Invalid JSON-LD syntax; lists of lists are not permitted.',
'jsonld.SyntaxError'); 'jsonld.SyntaxError', 'list of lists');
} }
} }
else { else {
@ -2336,8 +2352,9 @@ class JsonLdProcessor {
if(self::_isValue($item) || self::_isList($item)) { if(self::_isValue($item) || self::_isList($item)) {
throw new JsonLdException( throw new JsonLdException(
'Invalid JSON-LD syntax; "@reverse" value must not be a ' + 'Invalid JSON-LD syntax; "@reverse" value must not be a ' +
'@value or an @list.', '@value or an @list.', 'jsonld.SyntaxError',
'jsonld.SyntaxError', array('value' => $expanded_value)); 'invalid reverse property value',
array('value' => $expanded_value));
} }
self::addValue( self::addValue(
$reverse_map, $expanded_property, $item, $reverse_map, $expanded_property, $item,
@ -2368,7 +2385,8 @@ class JsonLdProcessor {
throw new JsonLdException( throw new JsonLdException(
'Invalid JSON-LD syntax; an element containing "@value" may not ' . 'Invalid JSON-LD syntax; an element containing "@value" may not ' .
'contain both "@type" and "@language".', 'contain both "@type" and "@language".',
'jsonld.SyntaxError', array('element' => $rval)); 'jsonld.SyntaxError', 'invalid value object',
array('element' => $rval));
} }
$valid_count = $count - 1; $valid_count = $count - 1;
if(property_exists($rval, '@type')) { if(property_exists($rval, '@type')) {
@ -2385,16 +2403,29 @@ class JsonLdProcessor {
'Invalid JSON-LD syntax; an element containing "@value" may only ' . 'Invalid JSON-LD syntax; an element containing "@value" may only ' .
'have an "@index" property and at most one other property ' . 'have an "@index" property and at most one other property ' .
'which can be "@type" or "@language".', 'which can be "@type" or "@language".',
'jsonld.SyntaxError', array('element' => $rval)); 'jsonld.SyntaxError', 'invalid value object',
array('element' => $rval));
} }
// drop null @values // drop null @values
if($rval->{'@value'} === null) { if($rval->{'@value'} === null) {
$rval = null; $rval = null;
} }
// drop @language if @value isn't a string // if @language is present, @value must be a string
else if(property_exists($rval, '@language') && else if(property_exists($rval, '@language') &&
!is_string($rval->{'@value'})) { !is_string($rval->{'@value'})) {
unset($rval->{'@language'}); throw new JsonLdException(
'Invalid JSON-LD syntax; only strings may be language-tagged.',
'jsonld.SyntaxError', 'invalid language-tagged value',
array('element' => $rval));
}
else if(property_exists($rval, '@type') &&
!self::_isAbsoluteIri($rval->{'@type'}) ||
strpos($rval->{'@type'}, '_:') === 0) {
throw new JsonLdException(
'Invalid JSON-LD syntax; an element containing "@value" ' .
'and "@type" must have an absolute IRI for the value ' .
'of "@type".', 'jsonld.SyntaxError', 'invalid typed value',
array('element' => $rval));
} }
} }
// convert @type to an array // convert @type to an array
@ -2408,8 +2439,8 @@ class JsonLdProcessor {
throw new JsonLdException( throw new JsonLdException(
'Invalid JSON-LD syntax; if an element has the property "@set" ' . 'Invalid JSON-LD syntax; if an element has the property "@set" ' .
'or "@list", then it can have at most one other property that is ' . 'or "@list", then it can have at most one other property that is ' .
'"@index".', '"@index".', 'jsonld.SyntaxError', 'invalid set or list object',
'jsonld.SyntaxError', array('element' => $rval)); array('element' => $rval));
} }
// optimize away @set // optimize away @set
if(property_exists($rval, '@set')) { if(property_exists($rval, '@set')) {
@ -2427,24 +2458,12 @@ class JsonLdProcessor {
if(is_object($rval) && if(is_object($rval) &&
!$options['keepFreeFloatingNodes'] && !$inside_list && !$options['keepFreeFloatingNodes'] && !$inside_list &&
($active_property === null || $expanded_active_property === '@graph')) { ($active_property === null || $expanded_active_property === '@graph')) {
// drop empty object or top-level @value // drop empty object or top-level @value/@list, or object with only @id
if($count === 0 || property_exists($rval, '@value')) { if($count === 0 || property_exists($rval, '@value') ||
property_exists($rval, '@list') ||
($count === 1 && property_exists($rval, '@id'))) {
$rval = null; $rval = null;
} }
else {
// drop subjects that generate no triples
$has_triples = false;
$ignore = array('@graph', '@type');
foreach($keys as $key) {
if(!self::_isKeyword($key) || in_array($key, $ignore)) {
$has_triples = true;
break;
}
}
if(!$has_triples) {
$rval = null;
}
}
} }
return $rval; return $rval;
@ -5430,9 +5449,9 @@ jsonld_register_rdf_parser(
*/ */
class JsonLdException extends Exception { class JsonLdException extends Exception {
public function __construct( public function __construct(
$msg, $type, /*$code='error',*/ $details=null, $previous=null) { $msg, $type, $code='error', $details=null, $previous=null) {
$this->type = $type; $this->type = $type;
//$this->code = $code; $this->code = $code;
$this->details = $details; $this->details = $details;
$this->cause = $previous; $this->cause = $previous;
parent::__construct($msg, 0, $previous); parent::__construct($msg, 0, $previous);