Add new framing features.

- Allow filtering based on a specific @id.
- Allow ducktyping matches on @type: [{}].
- Allow ducktyping matches when a @default is specified.
- Add @requireAll flag for controlling ducktyping requirements.
This commit is contained in:
Dave Longley 2014-07-29 13:40:31 -04:00
parent ba16da5b9f
commit 3402d51dff

View file

@ -94,6 +94,7 @@ function jsonld_flatten($input, $ctx, $options=array()) {
* [base] the base IRI to use. * [base] the base IRI to use.
* [embed] default @embed flag (default: true). * [embed] default @embed flag (default: true).
* [explicit] default @explicit flag (default: false). * [explicit] default @explicit flag (default: false).
* [requireAll] default @requireAll flag (default: true).
* [omitDefault] default @omitDefault flag (default: false). * [omitDefault] default @omitDefault flag (default: false).
* [documentLoader(url)] the document loader. * [documentLoader(url)] the document loader.
* *
@ -1076,6 +1077,7 @@ class JsonLdProcessor {
* [expandContext] a context to expand with. * [expandContext] a context to expand with.
* [embed] default @embed flag (default: true). * [embed] default @embed flag (default: true).
* [explicit] default @explicit flag (default: false). * [explicit] default @explicit flag (default: false).
* [requireAll] default @requireAll flag (default: true).
* [omitDefault] default @omitDefault flag (default: false). * [omitDefault] default @omitDefault flag (default: false).
* [documentLoader(url)] the document loader. * [documentLoader(url)] the document loader.
* *
@ -1088,6 +1090,7 @@ class JsonLdProcessor {
'compactArrays' => true, 'compactArrays' => true,
'embed' => true, 'embed' => true,
'explicit' => false, 'explicit' => false,
'requireAll' => true,
'omitDefault' => false, 'omitDefault' => false,
'documentLoader' => $jsonld_default_load_document)); 'documentLoader' => $jsonld_default_load_document));
@ -3679,13 +3682,18 @@ class JsonLdProcessor {
$this->_validateFrame($state, $frame); $this->_validateFrame($state, $frame);
$frame = $frame[0]; $frame = $frame[0];
// filter out subjects that match the frame
$matches = $this->_filterSubjects($state, $subjects, $frame);
// get flags for current frame // get flags for current frame
$options = $state->options; $options = $state->options;
$embed_on = $this->_getFrameFlag($frame, $options, 'embed'); $embed_on = $this->_getFrameFlag($frame, $options, 'embed');
$explicit_on = $this->_getFrameFlag($frame, $options, 'explicit'); $explicit_on = $this->_getFrameFlag($frame, $options, 'explicit');
$require_all_on = $this->_getFrameFlag($frame, $options, 'requireAll');
$flags = array(
'embed' => $embed_on,
'explicit' => $explicit_on,
'requireAll' => $require_all_on);
// filter out subjects that match the frame
$matches = $this->_filterSubjects($state, $subjects, $frame, $flags);
// add matches to output // add matches to output
foreach($matches as $id => $subject) { foreach($matches as $id => $subject) {
@ -3859,15 +3867,16 @@ class JsonLdProcessor {
* @param stdClass $state the current framing state. * @param stdClass $state the current framing state.
* @param array $subjects the set of subjects to filter. * @param array $subjects the set of subjects to filter.
* @param stdClass $frame the parsed frame. * @param stdClass $frame the parsed frame.
* @param assoc $flags the frame flags.
* *
* @return stdClass all of the matched subjects. * @return stdClass all of the matched subjects.
*/ */
protected function _filterSubjects($state, $subjects, $frame) { protected function _filterSubjects($state, $subjects, $frame, $flags) {
$rval = new stdClass(); $rval = new stdClass();
sort($subjects); sort($subjects);
foreach($subjects as $id) { foreach($subjects as $id) {
$subject = $state->subjects->{$id}; $subject = $state->subjects->{$id};
if($this->_filterSubject($subject, $frame)) { if($this->_filterSubject($subject, $frame, $flags)) {
$rval->{$id} = $subject; $rval->{$id} = $subject;
} }
} }
@ -3879,10 +3888,11 @@ class JsonLdProcessor {
* *
* @param stdClass $subject the subject to check. * @param stdClass $subject the subject to check.
* @param stdClass $frame the frame to check. * @param stdClass $frame the frame to check.
* @param assoc $flags the frame flags.
* *
* @return bool true if the subject matches, false if not. * @return bool true if the subject matches, false if not.
*/ */
protected function _filterSubject($subject, $frame) { protected function _filterSubject($subject, $frame, $flags) {
// check @type (object value means 'any' type, fall through to ducktyping) // check @type (object value means 'any' type, fall through to ducktyping)
if(property_exists($frame, '@type') && if(property_exists($frame, '@type') &&
!(count($frame->{'@type'}) === 1 && is_object($frame->{'@type'}[0]))) { !(count($frame->{'@type'}) === 1 && is_object($frame->{'@type'}[0]))) {
@ -3897,14 +3907,47 @@ class JsonLdProcessor {
} }
// check ducktype // check ducktype
$wildcard = true;
$matches_some = false;
foreach($frame as $k => $v) { foreach($frame as $k => $v) {
// only not a duck if @id or non-keyword isn't in subject if(self::_isKeyword($k)) {
if(($k === '@id' || !self::_isKeyword($k)) && // skip non-@id and non-@type
!property_exists($subject, $k)) { if($k !== '@id' && $k !== '@type') {
continue;
}
$wildcard = false;
// check @id for a specific @id value
if($k === '@id' && is_string($v)) {
if(!property_exists($subject, $k) || $subject->{$k} !== $v) {
return false;
}
$matches_some = true;
continue;
}
}
$wildcard = false;
if(property_exists($subject, $k)) {
// $v === [] means do not match if property is present
if(is_array($v) && count($v) === 0) {
return false;
}
$matches_some = true;
continue;
}
// all properties must match to be a duck unless a @default is specified
$has_default = (is_array($v) && count($v) === 1 && is_object($v[0]) &&
property_exists($v[0], '@default'));
if($flags['requireAll'] && !$has_default) {
return false; return false;
} }
} }
return true;
// return true if wildcard or subject matches some properties
return $wildcard || $matches_some;
} }
/** /**
@ -5325,6 +5368,7 @@ class JsonLdProcessor {
case '@list': case '@list':
case '@omitDefault': case '@omitDefault':
case '@preserve': case '@preserve':
case '@requireAll':
case '@reverse': case '@reverse':
case '@set': case '@set':
case '@type': case '@type':