forked from friendica/php-json-ld
Bump version.
This commit is contained in:
parent
b53300d179
commit
d80c0acb4f
1 changed files with 1032 additions and 1032 deletions
2064
jsonld.php
2064
jsonld.php
|
|
@ -1,7 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* PHP implementation of the JSON-LD API.
|
* PHP implementation of the JSON-LD API.
|
||||||
* Version: 0.0.2
|
* Version: 0.0.3
|
||||||
*
|
*
|
||||||
* @author Dave Longley
|
* @author Dave Longley
|
||||||
*
|
*
|
||||||
|
|
@ -70,22 +70,22 @@ function jsonld_expand($input, $options=array()) {
|
||||||
return $p->expand($input, $options);
|
return $p->expand($input, $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs JSON-LD flattening.
|
* Performs JSON-LD flattening.
|
||||||
*
|
|
||||||
* @param mixed $input the JSON-LD to flatten.
|
|
||||||
* @param mixed $ctx the context to use to compact the flattened output, or
|
|
||||||
* null.
|
|
||||||
* @param [options] the options to use:
|
|
||||||
* [base] the base IRI to use.
|
|
||||||
* [urlClient(url)] the URL client to use.
|
|
||||||
*
|
*
|
||||||
* @return mixed the flattened JSON-LD output.
|
* @param mixed $input the JSON-LD to flatten.
|
||||||
*/
|
* @param mixed $ctx the context to use to compact the flattened output, or
|
||||||
|
* null.
|
||||||
|
* @param [options] the options to use:
|
||||||
|
* [base] the base IRI to use.
|
||||||
|
* [urlClient(url)] the URL client to use.
|
||||||
|
*
|
||||||
|
* @return mixed the flattened JSON-LD output.
|
||||||
|
*/
|
||||||
function jsonld_flatten($input, $ctx, $options=array()) {
|
function jsonld_flatten($input, $ctx, $options=array()) {
|
||||||
$p = new JsonLdProcessor();
|
$p = new JsonLdProcessor();
|
||||||
return $p->flatten($input, $ctx, $options);
|
return $p->flatten($input, $ctx, $options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs JSON-LD framing.
|
* Performs JSON-LD framing.
|
||||||
|
|
@ -210,66 +210,66 @@ function jsonld_get_url($url) {
|
||||||
return jsonld_default_get_url($url);
|
return jsonld_default_get_url($url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default implementation to retrieve JSON-LD at the given URL.
|
* The default implementation to retrieve JSON-LD at the given URL.
|
||||||
*
|
*
|
||||||
* @param string $url the URL to to retrieve.
|
* @param string $url the URL to to retrieve.
|
||||||
*
|
*
|
||||||
* @return the JSON-LD.
|
* @return the JSON-LD.
|
||||||
*/
|
*/
|
||||||
function jsonld_default_get_url($url) {
|
function jsonld_default_get_url($url) {
|
||||||
// default JSON-LD GET implementation
|
// default JSON-LD GET implementation
|
||||||
$opts = array('http' =>
|
$opts = array('http' =>
|
||||||
array(
|
array(
|
||||||
'method' => "GET",
|
'method' => "GET",
|
||||||
'header' =>
|
'header' =>
|
||||||
"Accept: application/ld+json\r\n" .
|
"Accept: application/ld+json\r\n" .
|
||||||
"User-Agent: PaySwarm PHP Client/1.0\r\n"));
|
"User-Agent: PaySwarm PHP Client/1.0\r\n"));
|
||||||
$stream = stream_context_create($opts);
|
$stream = stream_context_create($opts);
|
||||||
$result = @file_get_contents($url, false, $stream);
|
$result = @file_get_contents($url, false, $stream);
|
||||||
if($result === false) {
|
if($result === false) {
|
||||||
throw new Exception("Could not GET url: '$url'");
|
throw new Exception("Could not GET url: '$url'");
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
|
||||||
|
|
||||||
/** Registered global RDF Statement parsers hashed by content-type. */
|
|
||||||
global $jsonld_rdf_parsers;
|
|
||||||
$jsonld_rdf_parsers = new stdClass();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a global RDF Statement parser by content-type, for use with
|
|
||||||
* jsonld_from_rdf. Global parsers will be used by JsonLdProcessors that do
|
|
||||||
* not register their own parsers.
|
|
||||||
*
|
|
||||||
* @param string $content_type the content-type for the parser.
|
|
||||||
* @param callable $parser(input) the parser function (takes a string as
|
|
||||||
* a parameter and returns an array of RDF statements).
|
|
||||||
*/
|
|
||||||
function jsonld_register_rdf_parser($content_type, $parser) {
|
|
||||||
global $jsonld_rdf_parsers;
|
|
||||||
$jsonld_rdf_parsers->{$content_type} = $parser;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unregisters a global RDF Statement parser by content-type.
|
|
||||||
*
|
|
||||||
* @param string $content_type the content-type for the parser.
|
|
||||||
*/
|
|
||||||
function jsonld_unregister_rdf_parser($content_type) {
|
|
||||||
global $jsonld_rdf_parsers;
|
|
||||||
if(property_exists($jsonld_rdf_parsers, $content_type)) {
|
|
||||||
unset($jsonld_rdf_parsers->{$content_type});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Registered global RDF Statement parsers hashed by content-type. */
|
||||||
* Parses a URL into its component parts.
|
global $jsonld_rdf_parsers;
|
||||||
*
|
$jsonld_rdf_parsers = new stdClass();
|
||||||
* @param string $url the URL to parse.
|
|
||||||
*
|
/**
|
||||||
* @return assoc the parsed URL.
|
* Registers a global RDF Statement parser by content-type, for use with
|
||||||
*/
|
* jsonld_from_rdf. Global parsers will be used by JsonLdProcessors that do
|
||||||
|
* not register their own parsers.
|
||||||
|
*
|
||||||
|
* @param string $content_type the content-type for the parser.
|
||||||
|
* @param callable $parser(input) the parser function (takes a string as
|
||||||
|
* a parameter and returns an array of RDF statements).
|
||||||
|
*/
|
||||||
|
function jsonld_register_rdf_parser($content_type, $parser) {
|
||||||
|
global $jsonld_rdf_parsers;
|
||||||
|
$jsonld_rdf_parsers->{$content_type} = $parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters a global RDF Statement parser by content-type.
|
||||||
|
*
|
||||||
|
* @param string $content_type the content-type for the parser.
|
||||||
|
*/
|
||||||
|
function jsonld_unregister_rdf_parser($content_type) {
|
||||||
|
global $jsonld_rdf_parsers;
|
||||||
|
if(property_exists($jsonld_rdf_parsers, $content_type)) {
|
||||||
|
unset($jsonld_rdf_parsers->{$content_type});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a URL into its component parts.
|
||||||
|
*
|
||||||
|
* @param string $url the URL to parse.
|
||||||
|
*
|
||||||
|
* @return assoc the parsed URL.
|
||||||
|
*/
|
||||||
function jsonld_parse_url($url) {
|
function jsonld_parse_url($url) {
|
||||||
$rval = parse_url($url);
|
$rval = parse_url($url);
|
||||||
if(isset($rval['host'])) {
|
if(isset($rval['host'])) {
|
||||||
|
|
@ -307,96 +307,96 @@ function jsonld_parse_url($url) {
|
||||||
* @return string the absolute IRI.
|
* @return string the absolute IRI.
|
||||||
*/
|
*/
|
||||||
function jsonld_prepend_base($base, $iri) {
|
function jsonld_prepend_base($base, $iri) {
|
||||||
// already an absolute IRI
|
// already an absolute IRI
|
||||||
if(strpos($iri, ':') !== false) {
|
if(strpos($iri, ':') !== false) {
|
||||||
return $iri;
|
return $iri;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(is_string($base)) {
|
if(is_string($base)) {
|
||||||
$base = jsonld_parse_url($base);
|
$base = jsonld_parse_url($base);
|
||||||
}
|
}
|
||||||
$authority = $base['host'];
|
$authority = $base['host'];
|
||||||
if(isset($base['port'])) {
|
if(isset($base['port'])) {
|
||||||
$authority .= ":{$base['port']}";
|
$authority .= ":{$base['port']}";
|
||||||
}
|
}
|
||||||
$rel = jsonld_parse_url($iri);
|
$rel = jsonld_parse_url($iri);
|
||||||
|
|
||||||
// per RFC3986 normalize slashes and dots in path
|
// per RFC3986 normalize slashes and dots in path
|
||||||
|
|
||||||
// IRI contains authority
|
// IRI contains authority
|
||||||
if(strpos($iri, '//') === 0) {
|
if(strpos($iri, '//') === 0) {
|
||||||
$path = substr($iri, 2);
|
$path = substr($iri, 2);
|
||||||
$authority = substr($path, 0, strrpos($path, '/'));
|
$authority = substr($path, 0, strrpos($path, '/'));
|
||||||
$path = substr($path, strlen($authority));
|
$path = substr($path, strlen($authority));
|
||||||
}
|
}
|
||||||
// IRI represents an absolute path
|
// IRI represents an absolute path
|
||||||
else if(strpos($rel['path'], '/') === 0) {
|
else if(strpos($rel['path'], '/') === 0) {
|
||||||
$path = $rel['path'];
|
$path = $rel['path'];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$path = $base['path'];
|
$path = $base['path'];
|
||||||
|
|
||||||
// prepend last directory for base
|
// prepend last directory for base
|
||||||
if($rel['path'] !== '') {
|
if($rel['path'] !== '') {
|
||||||
$idx = strrpos($path, '/');
|
$idx = strrpos($path, '/');
|
||||||
$idx = ($idx === false) ? 0 : $idx + 1;
|
$idx = ($idx === false) ? 0 : $idx + 1;
|
||||||
$path = substr($path, 0, $idx) . $rel['path'];
|
$path = substr($path, 0, $idx) . $rel['path'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$segments = explode('/', $path);
|
$segments = explode('/', $path);
|
||||||
|
|
||||||
// remove '.' and '' (do not remove trailing empty path)
|
// remove '.' and '' (do not remove trailing empty path)
|
||||||
$idx = -1;
|
$idx = -1;
|
||||||
$end = count($segments) - 1;
|
$end = count($segments) - 1;
|
||||||
$filter = function($e) use (&$idx, $end) {
|
$filter = function($e) use (&$idx, $end) {
|
||||||
$idx += 1;
|
$idx += 1;
|
||||||
return $e !== '.' && ($e !== '' || $idx === $end);
|
return $e !== '.' && ($e !== '' || $idx === $end);
|
||||||
};
|
};
|
||||||
$segments = array_values(array_filter($segments, $filter));
|
$segments = array_values(array_filter($segments, $filter));
|
||||||
|
|
||||||
// remove as many '..' as possible
|
// remove as many '..' as possible
|
||||||
for($i = 0; $i < count($segments);) {
|
for($i = 0; $i < count($segments);) {
|
||||||
$segment = $segments[$i];
|
$segment = $segments[$i];
|
||||||
if($segment === '..') {
|
if($segment === '..') {
|
||||||
// too many reverse dots
|
// too many reverse dots
|
||||||
if($i === 0) {
|
if($i === 0) {
|
||||||
$last = $segments[count($segments) - 1];
|
$last = $segments[count($segments) - 1];
|
||||||
if($last !== '..') {
|
if($last !== '..') {
|
||||||
$segments = array($last);
|
$segments = array($last);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$segments = array();
|
$segments = array();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove '..' and previous segment
|
// remove '..' and previous segment
|
||||||
array_splice($segments, $i - 1, 2);
|
array_splice($segments, $i - 1, 2);
|
||||||
$segments = array_values($segments);
|
$segments = array_values($segments);
|
||||||
$i -= 1;
|
$i -= 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$i += 1;
|
$i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$path = '/' . implode('/', $segments);
|
$path = '/' . implode('/', $segments);
|
||||||
|
|
||||||
// add query and hash
|
// add query and hash
|
||||||
if(isset($rel['query'])) {
|
if(isset($rel['query'])) {
|
||||||
$path .= "?{$rel['query']}";
|
$path .= "?{$rel['query']}";
|
||||||
}
|
}
|
||||||
if(isset($rel['fragment'])) {
|
if(isset($rel['fragment'])) {
|
||||||
$path .= "#{$rel['fragment']}";
|
$path .= "#{$rel['fragment']}";
|
||||||
}
|
}
|
||||||
|
|
||||||
$absolute_iri = "{$base['scheme']}://";
|
$absolute_iri = "{$base['scheme']}://";
|
||||||
if(isset($base['auth'])) {
|
if(isset($base['auth'])) {
|
||||||
$absolute_iri .= "{$base['auth']}@";
|
$absolute_iri .= "{$base['auth']}@";
|
||||||
}
|
}
|
||||||
$absolute_iri .= "$authority$path";
|
$absolute_iri .= "$authority$path";
|
||||||
|
|
||||||
return $absolute_iri;
|
return $absolute_iri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -557,9 +557,9 @@ class JsonLdProcessor {
|
||||||
$compacted = new stdClass();
|
$compacted = new stdClass();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// always use array if graph option is on
|
// always use array if graph option is on
|
||||||
else if($options['graph']) {
|
else if($options['graph']) {
|
||||||
$compacted = self::arrayify($compacted);
|
$compacted = self::arrayify($compacted);
|
||||||
}
|
}
|
||||||
|
|
||||||
// follow @context key
|
// follow @context key
|
||||||
|
|
@ -647,9 +647,9 @@ class JsonLdProcessor {
|
||||||
$input, new stdClass(), $options['urlClient'], $options['base']);
|
$input, new stdClass(), $options['urlClient'], $options['base']);
|
||||||
}
|
}
|
||||||
catch(Exception $e) {
|
catch(Exception $e) {
|
||||||
throw new JsonLdException(
|
throw new JsonLdException(
|
||||||
'Could not perform JSON-LD expansion.',
|
'Could not perform JSON-LD expansion.',
|
||||||
'jsonld.ExpandError', null, $e);
|
'jsonld.ExpandError', null, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// do expansion
|
// do expansion
|
||||||
|
|
@ -668,53 +668,53 @@ class JsonLdProcessor {
|
||||||
return self::arrayify($expanded);
|
return self::arrayify($expanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs JSON-LD flattening.
|
* Performs JSON-LD flattening.
|
||||||
*
|
*
|
||||||
* @param mixed $input the JSON-LD to flatten.
|
* @param mixed $input the JSON-LD to flatten.
|
||||||
* @param ctx the context to use to compact the flattened output, or null.
|
* @param ctx the context to use to compact the flattened output, or null.
|
||||||
* @param assoc $options the options to use:
|
* @param assoc $options the options to use:
|
||||||
* [base] the base IRI to use.
|
* [base] the base IRI to use.
|
||||||
* [urlClient(url)] the URL client to use.
|
* [urlClient(url)] the URL client to use.
|
||||||
*
|
*
|
||||||
* @return array the flattened output.
|
* @return array the flattened output.
|
||||||
*/
|
*/
|
||||||
public function flatten($input, $ctx, $options) {
|
public function flatten($input, $ctx, $options) {
|
||||||
// set default options
|
// set default options
|
||||||
isset($options['base']) or $options['base'] = '';
|
isset($options['base']) or $options['base'] = '';
|
||||||
isset($options['urlClient']) or $options['urlClient'] = 'jsonld_get_url';
|
isset($options['urlClient']) or $options['urlClient'] = 'jsonld_get_url';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// expand input
|
// expand input
|
||||||
$expanded = $this->expand($input, $options);
|
$expanded = $this->expand($input, $options);
|
||||||
}
|
}
|
||||||
catch(Exception $e) {
|
catch(Exception $e) {
|
||||||
throw new JsonLdException(
|
throw new JsonLdException(
|
||||||
'Could not expand input before flattening.',
|
'Could not expand input before flattening.',
|
||||||
'jsonld.FlattenError', null, $e);
|
'jsonld.FlattenError', null, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// do flattening
|
// do flattening
|
||||||
$flattened = $this->_flatten($expanded);
|
$flattened = $this->_flatten($expanded);
|
||||||
|
|
||||||
if($ctx === null) {
|
if($ctx === null) {
|
||||||
return $flattened;
|
return $flattened;
|
||||||
}
|
}
|
||||||
|
|
||||||
// compact result (force @graph option to true, skip expansion)
|
// compact result (force @graph option to true, skip expansion)
|
||||||
$options['graph'] = true;
|
$options['graph'] = true;
|
||||||
$options['skipExpansion'] = true;
|
$options['skipExpansion'] = true;
|
||||||
try {
|
try {
|
||||||
$compacted = $this->compact($flattened, $ctx, $options);
|
$compacted = $this->compact($flattened, $ctx, $options);
|
||||||
}
|
}
|
||||||
catch(Exception $e) {
|
catch(Exception $e) {
|
||||||
throw new JsonLdException(
|
throw new JsonLdException(
|
||||||
'Could not compact flattened output.',
|
'Could not compact flattened output.',
|
||||||
'jsonld.FlattenError', null, $e);
|
'jsonld.FlattenError', null, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $compacted;
|
return $compacted;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs JSON-LD framing.
|
* Performs JSON-LD framing.
|
||||||
|
|
@ -852,9 +852,9 @@ class JsonLdProcessor {
|
||||||
!property_exists($this->rdfParsers, $options['format'])) ||
|
!property_exists($this->rdfParsers, $options['format'])) ||
|
||||||
$this->rdfParsers === null &&
|
$this->rdfParsers === null &&
|
||||||
!property_exists($jsonld_rdf_parsers, $options['format'])) {
|
!property_exists($jsonld_rdf_parsers, $options['format'])) {
|
||||||
throw new JsonLdException(
|
throw new JsonLdException(
|
||||||
'Unknown input format.',
|
'Unknown input format.',
|
||||||
'jsonld.UnknownFormat', array('format' => $options['format']));
|
'jsonld.UnknownFormat', array('format' => $options['format']));
|
||||||
}
|
}
|
||||||
if($this->rdfParsers !== null) {
|
if($this->rdfParsers !== null) {
|
||||||
$callable = $this->rdfParsers->{$options['format']};
|
$callable = $this->rdfParsers->{$options['format']};
|
||||||
|
|
@ -939,14 +939,14 @@ class JsonLdProcessor {
|
||||||
public function processContext($active_ctx, $local_ctx, $options) {
|
public function processContext($active_ctx, $local_ctx, $options) {
|
||||||
// set default options
|
// set default options
|
||||||
isset($options['base']) or $options['base'] = '';
|
isset($options['base']) or $options['base'] = '';
|
||||||
isset($options['renameBlankNodes']) or $options['renameBlankNodes'] =
|
isset($options['renameBlankNodes']) or $options['renameBlankNodes'] =
|
||||||
true;
|
true;
|
||||||
isset($options['urlClient']) or $options['urlClient'] = 'jsonld_get_url';
|
isset($options['urlClient']) or $options['urlClient'] = 'jsonld_get_url';
|
||||||
|
|
||||||
// return initial context early for null context
|
// return initial context early for null context
|
||||||
if($local_ctx === null) {
|
if($local_ctx === null) {
|
||||||
return $this->_getInitialContext($options);
|
return $this->_getInitialContext($options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve URLs in local_ctx
|
// retrieve URLs in local_ctx
|
||||||
$ctx = self::copy($local_ctx);
|
$ctx = self::copy($local_ctx);
|
||||||
|
|
@ -957,11 +957,11 @@ class JsonLdProcessor {
|
||||||
$this->_retrieveContextUrls(
|
$this->_retrieveContextUrls(
|
||||||
$ctx, new stdClass(), $options['urlClient'], $options['base']);
|
$ctx, new stdClass(), $options['urlClient'], $options['base']);
|
||||||
}
|
}
|
||||||
catch(Exception $e) {
|
catch(Exception $e) {
|
||||||
throw new JsonLdException(
|
throw new JsonLdException(
|
||||||
'Could not process JSON-LD context.',
|
'Could not process JSON-LD context.',
|
||||||
'jsonld.ContextError', null, $e);
|
'jsonld.ContextError', null, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// process context
|
// process context
|
||||||
return $this->_processContext($active_ctx, $ctx, $options);
|
return $this->_processContext($active_ctx, $ctx, $options);
|
||||||
|
|
@ -1231,182 +1231,182 @@ class JsonLdProcessor {
|
||||||
return $rval;
|
return $rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses statements in the form of N-Quads.
|
* Parses statements in the form of N-Quads.
|
||||||
*
|
*
|
||||||
* @param string $input the N-Quads input to parse.
|
* @param string $input the N-Quads input to parse.
|
||||||
*
|
*
|
||||||
* @return array the resulting RDF statements.
|
* @return array the resulting RDF statements.
|
||||||
*/
|
*/
|
||||||
public static function parseNQuads($input) {
|
public static function parseNQuads($input) {
|
||||||
// define partial regexes
|
// define partial regexes
|
||||||
$iri = '(?:<([^:]+:[^>]*)>)';
|
$iri = '(?:<([^:]+:[^>]*)>)';
|
||||||
$bnode = '(_:(?:[A-Za-z][A-Za-z0-9]*))';
|
$bnode = '(_:(?:[A-Za-z][A-Za-z0-9]*))';
|
||||||
$plain = '"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"';
|
$plain = '"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"';
|
||||||
$datatype = "(?:\\^\\^$iri)";
|
$datatype = "(?:\\^\\^$iri)";
|
||||||
$language = '(?:@([a-z]+(?:-[a-z0-9]+)*))';
|
$language = '(?:@([a-z]+(?:-[a-z0-9]+)*))';
|
||||||
$literal = "(?:$plain(?:$datatype|$language)?)";
|
$literal = "(?:$plain(?:$datatype|$language)?)";
|
||||||
$ws = '[ \\t]';
|
$ws = '[ \\t]';
|
||||||
$eoln = '/(?:\r\n)|(?:\n)|(?:\r)/';
|
$eoln = '/(?:\r\n)|(?:\n)|(?:\r)/';
|
||||||
$empty = "/^$ws*$/";
|
$empty = "/^$ws*$/";
|
||||||
|
|
||||||
// define quad part regexes
|
// define quad part regexes
|
||||||
$subject = "(?:$iri|$bnode)$ws+";
|
$subject = "(?:$iri|$bnode)$ws+";
|
||||||
$property = "$iri$ws+";
|
$property = "$iri$ws+";
|
||||||
$object = "(?:$iri|$bnode|$literal)$ws*";
|
$object = "(?:$iri|$bnode|$literal)$ws*";
|
||||||
$graph = "(?:\\.|(?:(?:$iri|$bnode)$ws*\\.))";
|
$graph = "(?:\\.|(?:(?:$iri|$bnode)$ws*\\.))";
|
||||||
|
|
||||||
// full quad regex
|
// full quad regex
|
||||||
$quad = "/^$ws*$subject$property$object$graph$ws*$/";
|
$quad = "/^$ws*$subject$property$object$graph$ws*$/";
|
||||||
|
|
||||||
// build RDF statements
|
// build RDF statements
|
||||||
$statements = array();
|
$statements = array();
|
||||||
|
|
||||||
// split N-Quad input into lines
|
// split N-Quad input into lines
|
||||||
$lines = preg_split($eoln, $input);
|
$lines = preg_split($eoln, $input);
|
||||||
$line_number = 0;
|
$line_number = 0;
|
||||||
foreach($lines as $line) {
|
foreach($lines as $line) {
|
||||||
$line_number += 1;
|
$line_number += 1;
|
||||||
|
|
||||||
// skip empty lines
|
// skip empty lines
|
||||||
if(preg_match($empty, $line)) {
|
if(preg_match($empty, $line)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse quad
|
// parse quad
|
||||||
if(!preg_match($quad, $line, $match)) {
|
if(!preg_match($quad, $line, $match)) {
|
||||||
throw new JsonLdException(
|
throw new JsonLdException(
|
||||||
'Error while parsing N-Quads; invalid quad.',
|
'Error while parsing N-Quads; invalid quad.',
|
||||||
'jsonld.ParseError', array('line' => $line_number));
|
'jsonld.ParseError', array('line' => $line_number));
|
||||||
}
|
}
|
||||||
|
|
||||||
// create RDF statement
|
// create RDF statement
|
||||||
$s = (object)array(
|
$s = (object)array(
|
||||||
'subject' => new stdClass(),
|
'subject' => new stdClass(),
|
||||||
'property' => new stdClass(),
|
'property' => new stdClass(),
|
||||||
'object' => new stdClass());
|
'object' => new stdClass());
|
||||||
|
|
||||||
// get subject
|
// get subject
|
||||||
if($match[1] !== '') {
|
if($match[1] !== '') {
|
||||||
$s->subject->nominalValue = $match[1];
|
$s->subject->nominalValue = $match[1];
|
||||||
$s->subject->interfaceName = 'IRI';
|
$s->subject->interfaceName = 'IRI';
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
$s->subject->nominalValue = $match[2];
|
|
||||||
$s->subject->interfaceName = 'BlankNode';
|
|
||||||
}
|
|
||||||
|
|
||||||
// get property
|
|
||||||
$s->property->nominalValue = $match[3];
|
|
||||||
$s->property->interfaceName = 'IRI';
|
|
||||||
|
|
||||||
// get object
|
|
||||||
if($match[4] !== '') {
|
|
||||||
$s->object->nominalValue = $match[4];
|
|
||||||
$s->object->interfaceName = 'IRI';
|
|
||||||
}
|
|
||||||
else if($match[5] !== '') {
|
|
||||||
$s->object->nominalValue = $match[5];
|
|
||||||
$s->object->interfaceName = 'BlankNode';
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
$unescaped = str_replace(
|
$s->subject->nominalValue = $match[2];
|
||||||
|
$s->subject->interfaceName = 'BlankNode';
|
||||||
|
}
|
||||||
|
|
||||||
|
// get property
|
||||||
|
$s->property->nominalValue = $match[3];
|
||||||
|
$s->property->interfaceName = 'IRI';
|
||||||
|
|
||||||
|
// get object
|
||||||
|
if($match[4] !== '') {
|
||||||
|
$s->object->nominalValue = $match[4];
|
||||||
|
$s->object->interfaceName = 'IRI';
|
||||||
|
}
|
||||||
|
else if($match[5] !== '') {
|
||||||
|
$s->object->nominalValue = $match[5];
|
||||||
|
$s->object->interfaceName = 'BlankNode';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$unescaped = str_replace(
|
||||||
array('\"', '\t', '\n', '\r', '\\\\'),
|
array('\"', '\t', '\n', '\r', '\\\\'),
|
||||||
array('"', "\t", "\n", "\r", '\\'),
|
array('"', "\t", "\n", "\r", '\\'),
|
||||||
$match[6]);
|
$match[6]);
|
||||||
$s->object->nominalValue = $unescaped;
|
$s->object->nominalValue = $unescaped;
|
||||||
$s->object->interfaceName = 'LiteralNode';
|
$s->object->interfaceName = 'LiteralNode';
|
||||||
if(isset($match[7]) && $match[7] !== '') {
|
if(isset($match[7]) && $match[7] !== '') {
|
||||||
$s->object->datatype = (object)array(
|
$s->object->datatype = (object)array(
|
||||||
'nominalValue' => $match[7], 'interfaceName' => 'IRI');
|
'nominalValue' => $match[7], 'interfaceName' => 'IRI');
|
||||||
}
|
}
|
||||||
else if(isset($match[8]) && $match[8] !== '') {
|
else if(isset($match[8]) && $match[8] !== '') {
|
||||||
$s->object->language = $match[8];
|
$s->object->language = $match[8];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get graph
|
// get graph
|
||||||
if(isset($match[9]) && $match[9] !== '') {
|
if(isset($match[9]) && $match[9] !== '') {
|
||||||
$s->name = (object)array(
|
$s->name = (object)array(
|
||||||
'nominalValue' => $match[9], 'interfaceName' => 'IRI');
|
'nominalValue' => $match[9], 'interfaceName' => 'IRI');
|
||||||
}
|
}
|
||||||
else if(isset($match[10]) && $match[10] !== '') {
|
else if(isset($match[10]) && $match[10] !== '') {
|
||||||
$s->name = (object)array(
|
$s->name = (object)array(
|
||||||
'nominalValue' => $match[10], 'interfaceName' => 'BlankNode');
|
'nominalValue' => $match[10], 'interfaceName' => 'BlankNode');
|
||||||
}
|
}
|
||||||
|
|
||||||
// add statement
|
// add statement
|
||||||
self::_appendUniqueRdfStatement($statements, $s);
|
self::_appendUniqueRdfStatement($statements, $s);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $statements;
|
return $statements;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts an RDF statement to an N-Quad string (a single quad).
|
* Converts an RDF statement to an N-Quad string (a single quad).
|
||||||
*
|
*
|
||||||
* @param stdClass $statement the RDF statement to convert.
|
* @param stdClass $statement the RDF statement to convert.
|
||||||
* @param string $bnode the bnode the statement is mapped to (optional, for
|
* @param string $bnode the bnode the statement is mapped to (optional, for
|
||||||
* use during normalization only).
|
* use during normalization only).
|
||||||
*
|
*
|
||||||
* @return the N-Quad string.
|
* @return the N-Quad string.
|
||||||
*/
|
*/
|
||||||
public static function toNQuad($statement, $bnode=null) {
|
public static function toNQuad($statement, $bnode=null) {
|
||||||
$s = $statement->subject;
|
$s = $statement->subject;
|
||||||
$p = $statement->property;
|
$p = $statement->property;
|
||||||
$o = $statement->object;
|
$o = $statement->object;
|
||||||
$g = property_exists($statement, 'name') ? $statement->name : null;
|
$g = property_exists($statement, 'name') ? $statement->name : null;
|
||||||
|
|
||||||
$quad = '';
|
$quad = '';
|
||||||
|
|
||||||
// subject is an IRI or bnode
|
// subject is an IRI or bnode
|
||||||
if($s->interfaceName === 'IRI') {
|
if($s->interfaceName === 'IRI') {
|
||||||
$quad .= "<{$s->nominalValue}>";
|
$quad .= "<{$s->nominalValue}>";
|
||||||
}
|
}
|
||||||
// normalization mode
|
// normalization mode
|
||||||
else if($bnode !== null) {
|
else if($bnode !== null) {
|
||||||
$quad .= ($s->nominalValue === $bnode) ? '_:a' : '_:z';
|
$quad .= ($s->nominalValue === $bnode) ? '_:a' : '_:z';
|
||||||
}
|
}
|
||||||
// normal mode
|
// normal mode
|
||||||
else {
|
|
||||||
$quad .= $s->nominalValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// property is always an IRI
|
|
||||||
$quad .= " <{$p->nominalValue}> ";
|
|
||||||
|
|
||||||
// object is IRI, bnode, or literal
|
|
||||||
if($o->interfaceName === 'IRI') {
|
|
||||||
$quad .= "<{$o->nominalValue}>";
|
|
||||||
}
|
|
||||||
else if($o->interfaceName === 'BlankNode') {
|
|
||||||
// normalization mode
|
|
||||||
if($bnode !== null) {
|
|
||||||
$quad .= ($o->nominalValue === $bnode) ? '_:a' : '_:z';
|
|
||||||
}
|
|
||||||
// normal mode
|
|
||||||
else {
|
|
||||||
$quad .= $o->nominalValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
$escaped = str_replace(
|
$quad .= $s->nominalValue;
|
||||||
array('\\', "\t", "\n", "\r", '"'),
|
}
|
||||||
array('\\\\', '\t', '\n', '\r', '\"'),
|
|
||||||
$o->nominalValue);
|
// property is always an IRI
|
||||||
$quad .= '"' . $escaped . '"';
|
$quad .= " <{$p->nominalValue}> ";
|
||||||
|
|
||||||
|
// object is IRI, bnode, or literal
|
||||||
|
if($o->interfaceName === 'IRI') {
|
||||||
|
$quad .= "<{$o->nominalValue}>";
|
||||||
|
}
|
||||||
|
else if($o->interfaceName === 'BlankNode') {
|
||||||
|
// normalization mode
|
||||||
|
if($bnode !== null) {
|
||||||
|
$quad .= ($o->nominalValue === $bnode) ? '_:a' : '_:z';
|
||||||
|
}
|
||||||
|
// normal mode
|
||||||
|
else {
|
||||||
|
$quad .= $o->nominalValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$escaped = str_replace(
|
||||||
|
array('\\', "\t", "\n", "\r", '"'),
|
||||||
|
array('\\\\', '\t', '\n', '\r', '\"'),
|
||||||
|
$o->nominalValue);
|
||||||
|
$quad .= '"' . $escaped . '"';
|
||||||
if(property_exists($o, 'datatype') &&
|
if(property_exists($o, 'datatype') &&
|
||||||
$o->datatype->nominalValue !== self::XSD_STRING) {
|
$o->datatype->nominalValue !== self::XSD_STRING) {
|
||||||
$quad .= "^^<{$o->datatype->nominalValue}>";
|
$quad .= "^^<{$o->datatype->nominalValue}>";
|
||||||
}
|
}
|
||||||
else if(property_exists($o, 'language')) {
|
else if(property_exists($o, 'language')) {
|
||||||
$quad .= '@' . $o->language;
|
$quad .= '@' . $o->language;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// graph
|
// graph
|
||||||
if($g !== null) {
|
if($g !== null) {
|
||||||
if($g->interfaceName === 'IRI') {
|
if($g->interfaceName === 'IRI') {
|
||||||
$quad .= " <{$g->nominalValue}>";
|
$quad .= " <{$g->nominalValue}>";
|
||||||
}
|
}
|
||||||
else if($bnode) {
|
else if($bnode) {
|
||||||
|
|
@ -1414,35 +1414,35 @@ class JsonLdProcessor {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$quad .= " {$g->nominalValue}";
|
$quad .= " {$g->nominalValue}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$quad .= " .\n";
|
|
||||||
return $quad;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
$quad .= " .\n";
|
||||||
|
return $quad;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* Registers a processor-specific RDF Statement parser by content-type.
|
* Registers a processor-specific RDF Statement parser by content-type.
|
||||||
* Global parsers will no longer be used by this processor.
|
* Global parsers will no longer be used by this processor.
|
||||||
*
|
*
|
||||||
* @param string $content_type the content-type for the parser.
|
* @param string $content_type the content-type for the parser.
|
||||||
* @param callable $parser(input) the parser function (takes a string as
|
* @param callable $parser(input) the parser function (takes a string as
|
||||||
* a parameter and returns an array of RDF statements).
|
* a parameter and returns an array of RDF statements).
|
||||||
*/
|
*/
|
||||||
public function registerRDFParser($content_type, $parser) {
|
public function registerRDFParser($content_type, $parser) {
|
||||||
if($this->rdfParsers === null) {
|
if($this->rdfParsers === null) {
|
||||||
$this->rdfParsers = new stdClass();
|
$this->rdfParsers = new stdClass();
|
||||||
}
|
}
|
||||||
$this->rdfParsers->{$content_type} = $parser;
|
$this->rdfParsers->{$content_type} = $parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unregisters a process-specific RDF Statement parser by content-type. If
|
* Unregisters a process-specific RDF Statement parser by content-type. If
|
||||||
* there are no remaining processor-specific parsers, then the global
|
* there are no remaining processor-specific parsers, then the global
|
||||||
* parsers will be re-enabled.
|
* parsers will be re-enabled.
|
||||||
*
|
*
|
||||||
* @param string $content_type the content-type for the parser.
|
* @param string $content_type the content-type for the parser.
|
||||||
*/
|
*/
|
||||||
public function unregisterRDFParser($content_type) {
|
public function unregisterRDFParser($content_type) {
|
||||||
if($this->rdfParsers !== null &&
|
if($this->rdfParsers !== null &&
|
||||||
property_exists($this->rdfParsers, $content_type)) {
|
property_exists($this->rdfParsers, $content_type)) {
|
||||||
|
|
@ -1450,8 +1450,8 @@ class JsonLdProcessor {
|
||||||
if(count(get_object_vars($content_type)) === 0) {
|
if(count(get_object_vars($content_type)) === 0) {
|
||||||
$this->rdfParsers = null;
|
$this->rdfParsers = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If $value is an array, returns $value, otherwise returns an array
|
* If $value is an array, returns $value, otherwise returns an array
|
||||||
|
|
@ -1913,25 +1913,25 @@ class JsonLdProcessor {
|
||||||
'@list' => self::arrayify($expanded_value));
|
'@list' => self::arrayify($expanded_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
// add copy of value for each property from property generator
|
// add copy of value for each property from property generator
|
||||||
if(is_array($expanded_property)) {
|
if(is_array($expanded_property)) {
|
||||||
$expanded_value = $this->_labelBlankNodes(
|
$expanded_value = $this->_labelBlankNodes(
|
||||||
$active_ctx->namer, $expanded_value);
|
$active_ctx->namer, $expanded_value);
|
||||||
foreach($expanded_property as $iri) {
|
foreach($expanded_property as $iri) {
|
||||||
self::addValue(
|
self::addValue(
|
||||||
$rval, $iri, self::copy($expanded_value),
|
$rval, $iri, self::copy($expanded_value),
|
||||||
array('propertyIsArray' => true));
|
array('propertyIsArray' => true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// add value for property
|
// add value for property
|
||||||
else {
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1941,77 +1941,77 @@ class JsonLdProcessor {
|
||||||
|
|
||||||
// @value must only have @language or @type
|
// @value must only have @language or @type
|
||||||
if(property_exists($rval, '@value')) {
|
if(property_exists($rval, '@value')) {
|
||||||
// @value must only have @language or @type
|
// @value must only have @language or @type
|
||||||
if(property_exists($rval, '@type') &&
|
if(property_exists($rval, '@type') &&
|
||||||
property_exists($rval, '@language')) {
|
property_exists($rval, '@language')) {
|
||||||
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', array('element' => $rval));
|
||||||
}
|
|
||||||
$valid_count = $count - 1;
|
|
||||||
if(property_exists($rval, '@type')) {
|
|
||||||
$valid_count -= 1;
|
|
||||||
}
|
|
||||||
if(property_exists($rval, '@index')) {
|
|
||||||
$valid_count -= 1;
|
|
||||||
}
|
|
||||||
if(property_exists($rval, '@language')) {
|
|
||||||
$valid_count -= 1;
|
|
||||||
}
|
|
||||||
if($valid_count !== 0) {
|
|
||||||
throw new JsonLdException(
|
|
||||||
'Invalid JSON-LD syntax; an element containing "@value" may only ' .
|
|
||||||
'have an "@index" property and at most one other property ' .
|
|
||||||
'which can be "@type" or "@language".',
|
|
||||||
'jsonld.SyntaxError', array('element' => $rval));
|
|
||||||
}
|
|
||||||
// drop null @values
|
|
||||||
if($rval->{'@value'} === null) {
|
|
||||||
$rval = null;
|
|
||||||
}
|
|
||||||
// drop @language if @value isn't a string
|
|
||||||
else if(property_exists($rval, '@language') &&
|
|
||||||
!is_string($rval->{'@value'})) {
|
|
||||||
unset($rval->{'@language'});
|
|
||||||
}
|
}
|
||||||
}
|
$valid_count = $count - 1;
|
||||||
// convert @type to an array
|
if(property_exists($rval, '@type')) {
|
||||||
else if(property_exists($rval, '@type') && !is_array($rval->{'@type'})) {
|
$valid_count -= 1;
|
||||||
$rval->{'@type'} = array($rval->{'@type'});
|
}
|
||||||
}
|
if(property_exists($rval, '@index')) {
|
||||||
// handle @set and @list
|
$valid_count -= 1;
|
||||||
|
}
|
||||||
|
if(property_exists($rval, '@language')) {
|
||||||
|
$valid_count -= 1;
|
||||||
|
}
|
||||||
|
if($valid_count !== 0) {
|
||||||
|
throw new JsonLdException(
|
||||||
|
'Invalid JSON-LD syntax; an element containing "@value" may only ' .
|
||||||
|
'have an "@index" property and at most one other property ' .
|
||||||
|
'which can be "@type" or "@language".',
|
||||||
|
'jsonld.SyntaxError', array('element' => $rval));
|
||||||
|
}
|
||||||
|
// drop null @values
|
||||||
|
if($rval->{'@value'} === null) {
|
||||||
|
$rval = null;
|
||||||
|
}
|
||||||
|
// drop @language if @value isn't a string
|
||||||
|
else if(property_exists($rval, '@language') &&
|
||||||
|
!is_string($rval->{'@value'})) {
|
||||||
|
unset($rval->{'@language'});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// convert @type to an array
|
||||||
|
else if(property_exists($rval, '@type') && !is_array($rval->{'@type'})) {
|
||||||
|
$rval->{'@type'} = array($rval->{'@type'});
|
||||||
|
}
|
||||||
|
// handle @set and @list
|
||||||
else if(property_exists($rval, '@set') ||
|
else if(property_exists($rval, '@set') ||
|
||||||
property_exists($rval, '@list')) {
|
property_exists($rval, '@list')) {
|
||||||
if($count > 1 && ($count !== 2 && property_exists($rval, '@index'))) {
|
if($count > 1 && ($count !== 2 && property_exists($rval, '@index'))) {
|
||||||
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', array('element' => $rval));
|
'jsonld.SyntaxError', array('element' => $rval));
|
||||||
}
|
}
|
||||||
// optimize away @set
|
// optimize away @set
|
||||||
if(property_exists($rval, '@set')) {
|
if(property_exists($rval, '@set')) {
|
||||||
$rval = $rval->{'@set'};
|
$rval = $rval->{'@set'};
|
||||||
$keys = array_keys((array)$rval);
|
$keys = array_keys((array)$rval);
|
||||||
$count = count($keys);
|
$count = count($keys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// drop objects with only @language
|
// drop objects with only @language
|
||||||
else if($count === 1 && property_exists($rval, '@language')) {
|
else if($count === 1 && property_exists($rval, '@language')) {
|
||||||
$rval = null;
|
$rval = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// drop certain top-level objects that do not occur in lists
|
// drop certain top-level objects that do not occur in lists
|
||||||
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
|
||||||
if($count === 0 || property_exists($rval, '@value')) {
|
if($count === 0 || property_exists($rval, '@value')) {
|
||||||
$rval = null;
|
$rval = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// drop subjects that generate no triples
|
// drop subjects that generate no triples
|
||||||
$has_triples = false;
|
$has_triples = false;
|
||||||
$ignore = array('@graph', '@type');
|
$ignore = array('@graph', '@type');
|
||||||
foreach($keys as $key) {
|
foreach($keys as $key) {
|
||||||
|
|
@ -2019,23 +2019,23 @@ class JsonLdProcessor {
|
||||||
$has_triples = true;
|
$has_triples = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!$has_triples) {
|
if(!$has_triples) {
|
||||||
$rval = null;
|
$rval = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $rval;
|
return $rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
// drop top-level scalars that are not in lists
|
// drop top-level 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,
|
||||||
array('vocab' => true)) === '@graph')) {
|
array('vocab' => true)) === '@graph')) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// expand element according to value expansion rules
|
// expand element according to value expansion rules
|
||||||
return $this->_expandValue($active_ctx, $active_property, $element);
|
return $this->_expandValue($active_ctx, $active_property, $element);
|
||||||
|
|
@ -2049,42 +2049,42 @@ class JsonLdProcessor {
|
||||||
* @return array the flattened output.
|
* @return array the flattened output.
|
||||||
*/
|
*/
|
||||||
protected function _flatten($input) {
|
protected function _flatten($input) {
|
||||||
// produce a map of all subjects and name each bnode
|
// produce a map of all subjects and name each bnode
|
||||||
$namer = new UniqueNamer('_:t');
|
$namer = new UniqueNamer('_:t');
|
||||||
$graphs = (object)array('@default' => new stdClass());
|
$graphs = (object)array('@default' => new stdClass());
|
||||||
$this->_createNodeMap($input, $graphs, '@default', $namer);
|
$this->_createNodeMap($input, $graphs, '@default', $namer);
|
||||||
|
|
||||||
// add all non-default graphs to default graph
|
// add all non-default graphs to default graph
|
||||||
$default_graph = $graphs->{'@default'};
|
$default_graph = $graphs->{'@default'};
|
||||||
$graph_names = array_keys((array)$graphs);
|
$graph_names = array_keys((array)$graphs);
|
||||||
foreach($graph_names as $graph_name) {
|
foreach($graph_names as $graph_name) {
|
||||||
if($graph_name === '@default') {
|
if($graph_name === '@default') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$node_map = $graphs->{$graph_name};
|
$node_map = $graphs->{$graph_name};
|
||||||
if(!property_exists($default_graph, $graph_name)) {
|
if(!property_exists($default_graph, $graph_name)) {
|
||||||
$default_graph->{$graph_name} = (object)array(
|
$default_graph->{$graph_name} = (object)array(
|
||||||
'@id' => $graph_name, '@graph' => array());
|
'@id' => $graph_name, '@graph' => array());
|
||||||
}
|
}
|
||||||
$subject = $default_graph->{$graph_name};
|
$subject = $default_graph->{$graph_name};
|
||||||
if(!property_exists($subject, '@graph')) {
|
if(!property_exists($subject, '@graph')) {
|
||||||
$subject->{'@graph'} = array();
|
$subject->{'@graph'} = array();
|
||||||
}
|
}
|
||||||
$ids = array_keys((array)$node_map);
|
$ids = array_keys((array)$node_map);
|
||||||
sort($ids);
|
sort($ids);
|
||||||
foreach($ids as $id) {
|
foreach($ids as $id) {
|
||||||
$subject->{'@graph'}[] = $node_map->{$id};
|
$subject->{'@graph'}[] = $node_map->{$id};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// produce flattened output
|
// produce flattened output
|
||||||
$flattened = array();
|
$flattened = array();
|
||||||
$keys = array_keys((array)$default_graph);
|
$keys = array_keys((array)$default_graph);
|
||||||
sort($keys);
|
sort($keys);
|
||||||
foreach($keys as $key) {
|
foreach($keys as $key) {
|
||||||
$flattened[] = $default_graph->{$key};
|
$flattened[] = $default_graph->{$key};
|
||||||
}
|
}
|
||||||
return $flattened;
|
return $flattened;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -2146,7 +2146,7 @@ class JsonLdProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create canonical namer
|
// create canonical namer
|
||||||
$namer = new UniqueNamer('_:c14n');
|
$namer = new UniqueNamer('_:c14n');
|
||||||
|
|
||||||
|
|
@ -2431,87 +2431,87 @@ class JsonLdProcessor {
|
||||||
protected function _toRDF(
|
protected function _toRDF(
|
||||||
$element, $namer, $subject, $property, $graph, &$statements) {
|
$element, $namer, $subject, $property, $graph, &$statements) {
|
||||||
// recurse into arrays
|
// recurse into arrays
|
||||||
if(is_array($element)) {
|
if(is_array($element)) {
|
||||||
// recurse into arrays
|
// recurse into arrays
|
||||||
foreach($element as $e) {
|
foreach($element as $e) {
|
||||||
$this->_toRDF($e, $namer, $subject, $property, $graph, $statements);
|
$this->_toRDF($e, $namer, $subject, $property, $graph, $statements);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
// element must be an rdf:type IRI (@values covered above)
|
|
||||||
if(is_string($element)) {
|
|
||||||
// emit IRI
|
|
||||||
$statement = (object)array(
|
|
||||||
'subject' => self::copy($subject),
|
|
||||||
'property' => self::copy($property),
|
|
||||||
'object' => (object)array(
|
|
||||||
'nominalValue' => $element,
|
|
||||||
'interfaceName' => 'IRI'));
|
|
||||||
if($graph !== null) {
|
|
||||||
$statement->name = $graph;
|
|
||||||
}
|
|
||||||
self::_appendUniqueRdfStatement($statements, $statement);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert @list
|
// element must be an rdf:type IRI (@values covered above)
|
||||||
if(self::_isList($element)) {
|
if(is_string($element)) {
|
||||||
$list = $this->_makeLinkedList($element);
|
// emit IRI
|
||||||
$this->_toRDF($list, $namer, $subject, $property, $graph, $statements);
|
$statement = (object)array(
|
||||||
return;
|
'subject' => self::copy($subject),
|
||||||
|
'property' => self::copy($property),
|
||||||
|
'object' => (object)array(
|
||||||
|
'nominalValue' => $element,
|
||||||
|
'interfaceName' => 'IRI'));
|
||||||
|
if($graph !== null) {
|
||||||
|
$statement->name = $graph;
|
||||||
|
}
|
||||||
|
self::_appendUniqueRdfStatement($statements, $statement);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert @value to object
|
// convert @list
|
||||||
if(self::_isValue($element)) {
|
if(self::_isList($element)) {
|
||||||
$value = $element->{'@value'};
|
$list = $this->_makeLinkedList($element);
|
||||||
$datatype = (property_exists($element, '@type') ?
|
$this->_toRDF($list, $namer, $subject, $property, $graph, $statements);
|
||||||
$element->{'@type'} : null);
|
return;
|
||||||
if(is_bool($value) || is_double($value) || is_integer($value)) {
|
|
||||||
// convert to XSD datatypes as appropriate
|
|
||||||
if(is_bool($value)) {
|
|
||||||
$value = ($value ? 'true' : 'false');
|
|
||||||
$datatype or $datatype = self::XSD_BOOLEAN;
|
|
||||||
}
|
|
||||||
else if(is_double($value)) {
|
|
||||||
// canonical double representation
|
|
||||||
$value = preg_replace('/(\d)0*E\+?/', '$1E',
|
|
||||||
sprintf('%1.15E', $value));
|
|
||||||
$datatype or $datatype = self::XSD_DOUBLE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$value = strval($value);
|
|
||||||
$datatype or $datatype = self::XSD_INTEGER;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// default to xsd:string datatype
|
|
||||||
$datatype or $datatype = self::XSD_STRING;
|
|
||||||
|
|
||||||
$object = (object)array(
|
|
||||||
'nominalValue' => $value,
|
|
||||||
'interfaceName' => 'LiteralNode',
|
|
||||||
'datatype' => (object)array(
|
|
||||||
'nominalValue' => $datatype,
|
|
||||||
'interfaceName' => 'IRI'));
|
|
||||||
if(property_exists($element, '@language') &&
|
|
||||||
$datatype === self::XSD_STRING) {
|
|
||||||
$object->language = $element->{'@language'};
|
|
||||||
}
|
|
||||||
|
|
||||||
// emit literal
|
|
||||||
$statement = (object)array(
|
|
||||||
'subject' => self::copy($subject),
|
|
||||||
'property' => self::copy($property),
|
|
||||||
'object' => $object);
|
|
||||||
if($graph !== null) {
|
|
||||||
$statement->name = $graph;
|
|
||||||
}
|
|
||||||
self::_appendUniqueRdfStatement($statements, $statement);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: element must be a subject
|
// convert @value to object
|
||||||
|
if(self::_isValue($element)) {
|
||||||
|
$value = $element->{'@value'};
|
||||||
|
$datatype = (property_exists($element, '@type') ?
|
||||||
|
$element->{'@type'} : null);
|
||||||
|
if(is_bool($value) || is_double($value) || is_integer($value)) {
|
||||||
|
// convert to XSD datatypes as appropriate
|
||||||
|
if(is_bool($value)) {
|
||||||
|
$value = ($value ? 'true' : 'false');
|
||||||
|
$datatype or $datatype = self::XSD_BOOLEAN;
|
||||||
|
}
|
||||||
|
else if(is_double($value)) {
|
||||||
|
// canonical double representation
|
||||||
|
$value = preg_replace('/(\d)0*E\+?/', '$1E',
|
||||||
|
sprintf('%1.15E', $value));
|
||||||
|
$datatype or $datatype = self::XSD_DOUBLE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$value = strval($value);
|
||||||
|
$datatype or $datatype = self::XSD_INTEGER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// default to xsd:string datatype
|
||||||
|
$datatype or $datatype = self::XSD_STRING;
|
||||||
|
|
||||||
|
$object = (object)array(
|
||||||
|
'nominalValue' => $value,
|
||||||
|
'interfaceName' => 'LiteralNode',
|
||||||
|
'datatype' => (object)array(
|
||||||
|
'nominalValue' => $datatype,
|
||||||
|
'interfaceName' => 'IRI'));
|
||||||
|
if(property_exists($element, '@language') &&
|
||||||
|
$datatype === self::XSD_STRING) {
|
||||||
|
$object->language = $element->{'@language'};
|
||||||
|
}
|
||||||
|
|
||||||
|
// emit literal
|
||||||
|
$statement = (object)array(
|
||||||
|
'subject' => self::copy($subject),
|
||||||
|
'property' => self::copy($property),
|
||||||
|
'object' => $object);
|
||||||
|
if($graph !== null) {
|
||||||
|
$statement->name = $graph;
|
||||||
|
}
|
||||||
|
self::_appendUniqueRdfStatement($statements, $statement);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: element must be a subject
|
||||||
|
|
||||||
// get subject @id (generate one if it is a bnode)
|
// get subject @id (generate one if it is a bnode)
|
||||||
$id = property_exists($element, '@id') ? $element->{'@id'} : null;
|
$id = property_exists($element, '@id') ? $element->{'@id'} : null;
|
||||||
|
|
@ -2601,10 +2601,10 @@ class JsonLdProcessor {
|
||||||
$rval = self::_cloneActiveContext($active_ctx);
|
$rval = self::_cloneActiveContext($active_ctx);
|
||||||
|
|
||||||
// normalize local context to an array
|
// normalize local context to an array
|
||||||
if(is_object($local_ctx) && property_exists($local_ctx, '@context') &&
|
if(is_object($local_ctx) && property_exists($local_ctx, '@context') &&
|
||||||
is_array($local_ctx->{'@context'})) {
|
is_array($local_ctx->{'@context'})) {
|
||||||
$local_ctx = $local_ctx->{'@context'};
|
$local_ctx = $local_ctx->{'@context'};
|
||||||
}
|
}
|
||||||
$ctxs = self::arrayify($local_ctx);
|
$ctxs = self::arrayify($local_ctx);
|
||||||
|
|
||||||
// process each context in order
|
// process each context in order
|
||||||
|
|
@ -2859,7 +2859,7 @@ class JsonLdProcessor {
|
||||||
$rval->{'@value'} = true;
|
$rval->{'@value'} = true;
|
||||||
}
|
}
|
||||||
else if($rval->{'@value'} === 'false') {
|
else if($rval->{'@value'} === 'false') {
|
||||||
$rval->{'@value'} = false;
|
$rval->{'@value'} = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(is_numeric($rval->{'@value'})) {
|
else if(is_numeric($rval->{'@value'})) {
|
||||||
|
|
@ -2871,7 +2871,7 @@ class JsonLdProcessor {
|
||||||
}
|
}
|
||||||
else if($type === self::XSD_DOUBLE) {
|
else if($type === self::XSD_DOUBLE) {
|
||||||
$rval->{'@value'} = doubleval($rval->{'@value'});
|
$rval->{'@value'} = doubleval($rval->{'@value'});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// do not add native type
|
// do not add native type
|
||||||
if(!in_array($type, array(
|
if(!in_array($type, array(
|
||||||
|
|
@ -2936,9 +2936,9 @@ class JsonLdProcessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
// add non-object to list
|
// add non-object to list
|
||||||
if(!is_object($input)) {
|
if(!is_object($input)) {
|
||||||
if($list !== null) {
|
if($list !== null) {
|
||||||
$list[] = $input;
|
$list[] = $input;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -3482,189 +3482,189 @@ class JsonLdProcessor {
|
||||||
return $input;
|
return $input;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hashes all of the statements about a blank node.
|
* Hashes all of the statements about a blank node.
|
||||||
*
|
*
|
||||||
* @param string $id the ID of the bnode to hash statements for.
|
* @param string $id the ID of the bnode to hash statements for.
|
||||||
* @param stdClass $bnodes the mapping of bnodes to statements.
|
* @param stdClass $bnodes the mapping of bnodes to statements.
|
||||||
* @param UniqueNamer $namer the canonical bnode namer.
|
* @param UniqueNamer $namer the canonical bnode namer.
|
||||||
*
|
*
|
||||||
* @return string the new hash.
|
* @return string the new hash.
|
||||||
*/
|
*/
|
||||||
protected function _hashStatements($id, $bnodes, $namer) {
|
protected function _hashStatements($id, $bnodes, $namer) {
|
||||||
// return cached hash
|
// return cached hash
|
||||||
if(property_exists($bnodes->{$id}, 'hash')) {
|
if(property_exists($bnodes->{$id}, 'hash')) {
|
||||||
return $bnodes->{$id}->hash;
|
return $bnodes->{$id}->hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
// serialize all of bnode's statements
|
// serialize all of bnode's statements
|
||||||
$statements = $bnodes->{$id}->statements;
|
$statements = $bnodes->{$id}->statements;
|
||||||
$nquads = array();
|
$nquads = array();
|
||||||
foreach($statements as $statement) {
|
foreach($statements as $statement) {
|
||||||
$nquads[] = $this->toNQuad($statement, $id);
|
$nquads[] = $this->toNQuad($statement, $id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort serialized quads
|
// sort serialized quads
|
||||||
sort($nquads);
|
sort($nquads);
|
||||||
|
|
||||||
// cache and return hashed quads
|
// cache and return hashed quads
|
||||||
$hash = $bnodes->{$id}->hash = sha1(implode($nquads));
|
$hash = $bnodes->{$id}->hash = sha1(implode($nquads));
|
||||||
return $hash;
|
return $hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produces a hash for the paths of adjacent bnodes for a bnode,
|
* Produces a hash for the paths of adjacent bnodes for a bnode,
|
||||||
* incorporating all information about its subgraph of bnodes. This
|
* incorporating all information about its subgraph of bnodes. This
|
||||||
* method will recursively pick adjacent bnode permutations that produce the
|
* method will recursively pick adjacent bnode permutations that produce the
|
||||||
* lexicographically-least 'path' serializations.
|
* lexicographically-least 'path' serializations.
|
||||||
*
|
*
|
||||||
* @param string $id the ID of the bnode to hash paths for.
|
* @param string $id the ID of the bnode to hash paths for.
|
||||||
* @param stdClass $bnodes the map of bnode statements.
|
* @param stdClass $bnodes the map of bnode statements.
|
||||||
* @param UniqueNamer $namer the canonical bnode namer.
|
* @param UniqueNamer $namer the canonical bnode namer.
|
||||||
* @param UniqueNamer $path_namer the namer used to assign names to adjacent
|
* @param UniqueNamer $path_namer the namer used to assign names to adjacent
|
||||||
* bnodes.
|
* bnodes.
|
||||||
*
|
*
|
||||||
* @return stdClass the hash and path namer used.
|
* @return stdClass the hash and path namer used.
|
||||||
*/
|
*/
|
||||||
protected function _hashPaths($id, $bnodes, $namer, $path_namer) {
|
protected function _hashPaths($id, $bnodes, $namer, $path_namer) {
|
||||||
// create SHA-1 digest
|
// create SHA-1 digest
|
||||||
$md = hash_init('sha1');
|
$md = hash_init('sha1');
|
||||||
|
|
||||||
// group adjacent bnodes by hash, keep properties and references separate
|
// group adjacent bnodes by hash, keep properties and references separate
|
||||||
$groups = new stdClass();
|
$groups = new stdClass();
|
||||||
$statements = $bnodes->{$id}->statements;
|
$statements = $bnodes->{$id}->statements;
|
||||||
foreach($statements as $statement) {
|
foreach($statements as $statement) {
|
||||||
// get adjacent bnode
|
// get adjacent bnode
|
||||||
$bnode = $this->_getAdjacentBlankNodeName($statement->subject, $id);
|
$bnode = $this->_getAdjacentBlankNodeName($statement->subject, $id);
|
||||||
if($bnode !== null) {
|
if($bnode !== null) {
|
||||||
$direction = 'p';
|
$direction = 'p';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$bnode = $this->_getAdjacentBlankNodeName($statement->object, $id);
|
$bnode = $this->_getAdjacentBlankNodeName($statement->object, $id);
|
||||||
if($bnode !== null) {
|
if($bnode !== null) {
|
||||||
$direction = 'r';
|
$direction = 'r';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if($bnode !== null) {
|
if($bnode !== null) {
|
||||||
// get bnode name (try canonical, path, then hash)
|
// get bnode name (try canonical, path, then hash)
|
||||||
if($namer->isNamed($bnode)) {
|
if($namer->isNamed($bnode)) {
|
||||||
$name = $namer->getName($bnode);
|
$name = $namer->getName($bnode);
|
||||||
}
|
}
|
||||||
else if($path_namer->isNamed($bnode)) {
|
else if($path_namer->isNamed($bnode)) {
|
||||||
$name = $path_namer->getName($bnode);
|
$name = $path_namer->getName($bnode);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$name = $this->_hashStatements($bnode, $bnodes, $namer);
|
$name = $this->_hashStatements($bnode, $bnodes, $namer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// hash direction, property, and bnode name/hash
|
// hash direction, property, and bnode name/hash
|
||||||
$group_md = hash_init('sha1');
|
$group_md = hash_init('sha1');
|
||||||
hash_update($group_md, $direction);
|
hash_update($group_md, $direction);
|
||||||
hash_update($group_md, $statement->property->nominalValue);
|
hash_update($group_md, $statement->property->nominalValue);
|
||||||
hash_update($group_md, $name);
|
hash_update($group_md, $name);
|
||||||
$group_hash = hash_final($group_md);
|
$group_hash = hash_final($group_md);
|
||||||
|
|
||||||
// add bnode to hash group
|
// add bnode to hash group
|
||||||
if(property_exists($groups, $group_hash)) {
|
if(property_exists($groups, $group_hash)) {
|
||||||
$groups->{$group_hash}[] = $bnode;
|
$groups->{$group_hash}[] = $bnode;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$groups->{$group_hash} = array($bnode);
|
$groups->{$group_hash} = array($bnode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate over groups in sorted hash order
|
// iterate over groups in sorted hash order
|
||||||
$group_hashes = array_keys((array)$groups);
|
$group_hashes = array_keys((array)$groups);
|
||||||
sort($group_hashes);
|
sort($group_hashes);
|
||||||
foreach($group_hashes as $group_hash) {
|
foreach($group_hashes as $group_hash) {
|
||||||
// digest group hash
|
// digest group hash
|
||||||
hash_update($md, $group_hash);
|
hash_update($md, $group_hash);
|
||||||
|
|
||||||
// choose a path and namer from the permutations
|
// choose a path and namer from the permutations
|
||||||
$chosen_path = null;
|
$chosen_path = null;
|
||||||
$chosen_namer = null;
|
$chosen_namer = null;
|
||||||
$permutator = new Permutator($groups->{$group_hash});
|
$permutator = new Permutator($groups->{$group_hash});
|
||||||
while($permutator->hasNext()) {
|
while($permutator->hasNext()) {
|
||||||
$permutation = $permutator->next();
|
$permutation = $permutator->next();
|
||||||
$path_namer_copy = clone $path_namer;
|
$path_namer_copy = clone $path_namer;
|
||||||
|
|
||||||
// build adjacent path
|
// build adjacent path
|
||||||
$path = '';
|
$path = '';
|
||||||
$skipped = false;
|
$skipped = false;
|
||||||
$recurse = array();
|
$recurse = array();
|
||||||
foreach($permutation as $bnode) {
|
foreach($permutation as $bnode) {
|
||||||
// use canonical name if available
|
// use canonical name if available
|
||||||
if($namer->isNamed($bnode)) {
|
if($namer->isNamed($bnode)) {
|
||||||
$path .= $namer->getName($bnode);
|
$path .= $namer->getName($bnode);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// recurse if bnode isn't named in the path yet
|
// recurse if bnode isn't named in the path yet
|
||||||
if(!$path_namer_copy->isNamed($bnode)) {
|
if(!$path_namer_copy->isNamed($bnode)) {
|
||||||
$recurse[] = $bnode;
|
$recurse[] = $bnode;
|
||||||
}
|
}
|
||||||
$path .= $path_namer_copy->getName($bnode);
|
$path .= $path_namer_copy->getName($bnode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip permutation if path is already >= chosen path
|
// skip permutation if path is already >= chosen path
|
||||||
if($chosen_path !== null && strlen($path) >= strlen($chosen_path) &&
|
if($chosen_path !== null && strlen($path) >= strlen($chosen_path) &&
|
||||||
$path > $chosen_path) {
|
$path > $chosen_path) {
|
||||||
$skipped = true;
|
$skipped = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// recurse
|
// recurse
|
||||||
if(!$skipped) {
|
if(!$skipped) {
|
||||||
foreach($recurse as $bnode) {
|
foreach($recurse as $bnode) {
|
||||||
$result = $this->_hashPaths(
|
$result = $this->_hashPaths(
|
||||||
$bnode, $bnodes, $namer, $path_namer_copy);
|
$bnode, $bnodes, $namer, $path_namer_copy);
|
||||||
$path .= $path_namer_copy->getName($bnode);
|
$path .= $path_namer_copy->getName($bnode);
|
||||||
$path .= "<{$result->hash}>";
|
$path .= "<{$result->hash}>";
|
||||||
$path_namer_copy = $result->pathNamer;
|
$path_namer_copy = $result->pathNamer;
|
||||||
|
|
||||||
// skip permutation if path is already >= chosen path
|
// skip permutation if path is already >= chosen path
|
||||||
if($chosen_path !== null &&
|
if($chosen_path !== null &&
|
||||||
strlen($path) >= strlen($chosen_path) && $path > $chosen_path) {
|
strlen($path) >= strlen($chosen_path) && $path > $chosen_path) {
|
||||||
$skipped = true;
|
$skipped = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$skipped && ($chosen_path === null || $path < $chosen_path)) {
|
if(!$skipped && ($chosen_path === null || $path < $chosen_path)) {
|
||||||
$chosen_path = $path;
|
$chosen_path = $path;
|
||||||
$chosen_namer = $path_namer_copy;
|
$chosen_namer = $path_namer_copy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// digest chosen path and update namer
|
// digest chosen path and update namer
|
||||||
hash_update($md, $chosen_path);
|
hash_update($md, $chosen_path);
|
||||||
$path_namer = $chosen_namer;
|
$path_namer = $chosen_namer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return SHA-1 hash and path namer
|
// return SHA-1 hash and path namer
|
||||||
return (object)array(
|
return (object)array(
|
||||||
'hash' => hash_final($md), 'pathNamer' => $path_namer);
|
'hash' => hash_final($md), 'pathNamer' => $path_namer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper function that gets the blank node name from an RDF statement
|
* A helper function that gets the blank node name from an RDF statement
|
||||||
* node (subject or object). If the node is not a blank node or its
|
* node (subject or object). If the node is not a blank node or its
|
||||||
* nominal value does not match the given blank node ID, it will be
|
* nominal value does not match the given blank node ID, it will be
|
||||||
* returned.
|
* returned.
|
||||||
*
|
*
|
||||||
* @param stdClass $node the RDF statement node.
|
* @param stdClass $node the RDF statement node.
|
||||||
* @param string $id the ID of the blank node to look next to.
|
* @param string $id the ID of the blank node to look next to.
|
||||||
*
|
*
|
||||||
* @return mixed the adjacent blank node name or null if none was found.
|
* @return mixed the adjacent blank node name or null if none was found.
|
||||||
*/
|
*/
|
||||||
protected function _getAdjacentBlankNodeName($node, $id) {
|
protected function _getAdjacentBlankNodeName($node, $id) {
|
||||||
if($node->interfaceName === 'BlankNode' && $node->nominalValue !== $id) {
|
if($node->interfaceName === 'BlankNode' && $node->nominalValue !== $id) {
|
||||||
return $node->nominalValue;
|
return $node->nominalValue;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares two strings first based on length and then lexicographically.
|
* Compares two strings first based on length and then lexicographically.
|
||||||
|
|
@ -3713,23 +3713,23 @@ class JsonLdProcessor {
|
||||||
|
|
||||||
// options for the value of @type or @language,
|
// options for the value of @type or @language,
|
||||||
// determine for @id based on whether or not value compacts to a term
|
// determine for @id based on whether or not value compacts to a term
|
||||||
if($type_or_language_value === '@id' && self::_isSubjectReference($value)) {
|
if($type_or_language_value === '@id' && self::_isSubjectReference($value)) {
|
||||||
// try to compact value to a term
|
// try to compact value to a term
|
||||||
$term = $this->_compactIri(
|
$term = $this->_compactIri(
|
||||||
$active_ctx, $value->{'@id'}, null, array('vocab' => true));
|
$active_ctx, $value->{'@id'}, null, array('vocab' => true));
|
||||||
if(property_exists($active_ctx->mappings, $term) &&
|
if(property_exists($active_ctx->mappings, $term) &&
|
||||||
$active_ctx->mappings->{$term} &&
|
$active_ctx->mappings->{$term} &&
|
||||||
$active_ctx->mappings->{$term}->{'@id'} === $value->{'@id'}) {
|
$active_ctx->mappings->{$term}->{'@id'} === $value->{'@id'}) {
|
||||||
// prefer @vocab
|
// prefer @vocab
|
||||||
$options = array('@vocab', '@id', '@none');
|
$options = array('@vocab', '@id', '@none');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// prefer @id
|
// prefer @id
|
||||||
$options = array('@id', '@vocab', '@none');
|
$options = array('@id', '@vocab', '@none');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$options = array($type_or_language_value, '@none');
|
$options = array($type_or_language_value, '@none');
|
||||||
}
|
}
|
||||||
|
|
||||||
$term = null;
|
$term = null;
|
||||||
|
|
@ -3809,10 +3809,10 @@ class JsonLdProcessor {
|
||||||
// use inverse context to pick a term if iri is relative to vocab
|
// use inverse context to pick a term if iri is relative to vocab
|
||||||
if(isset($relative_to['vocab']) && $relative_to['vocab'] &&
|
if(isset($relative_to['vocab']) && $relative_to['vocab'] &&
|
||||||
property_exists($this->_getInverseContext($active_ctx), $iri)) {
|
property_exists($this->_getInverseContext($active_ctx), $iri)) {
|
||||||
$default_language = '@none';
|
$default_language = '@none';
|
||||||
if(property_exists($active_ctx, '@language')) {
|
if(property_exists($active_ctx, '@language')) {
|
||||||
$default_language = $active_ctx->{'@language'};
|
$default_language = $active_ctx->{'@language'};
|
||||||
}
|
}
|
||||||
|
|
||||||
// prefer @index if available in value
|
// prefer @index if available in value
|
||||||
$containers = array();
|
$containers = array();
|
||||||
|
|
@ -4492,167 +4492,167 @@ class JsonLdProcessor {
|
||||||
return $rval;
|
return $rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds all @context URLs in the given JSON-LD input.
|
* Finds all @context URLs in the given JSON-LD input.
|
||||||
*
|
*
|
||||||
* @param mixed $input the JSON-LD input.
|
* @param mixed $input the JSON-LD input.
|
||||||
* @param stdClass $urls a map of URLs (url => false/@contexts).
|
* @param stdClass $urls a map of URLs (url => false/@contexts).
|
||||||
* @param bool $replace true to replace the URLs in the given input with
|
* @param bool $replace true to replace the URLs in the given input with
|
||||||
* the @contexts from the urls map, false not to.
|
* the @contexts from the urls map, false not to.
|
||||||
* @param string $base the base URL to resolve relative URLs with.
|
* @param string $base the base URL to resolve relative URLs with.
|
||||||
*/
|
*/
|
||||||
protected function _findContextUrls($input, $urls, $replace, $base) {
|
protected function _findContextUrls($input, $urls, $replace, $base) {
|
||||||
if(is_array($input)) {
|
if(is_array($input)) {
|
||||||
foreach($input as $e) {
|
foreach($input as $e) {
|
||||||
$this->_findContextUrls($e, $urls, $replace, $base);
|
$this->_findContextUrls($e, $urls, $replace, $base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(is_object($input)) {
|
else if(is_object($input)) {
|
||||||
foreach($input as $k => &$v) {
|
foreach($input as $k => &$v) {
|
||||||
if($k !== '@context') {
|
if($k !== '@context') {
|
||||||
$this->_findContextUrls($v, $urls, $replace, $base);
|
$this->_findContextUrls($v, $urls, $replace, $base);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// array @context
|
// array @context
|
||||||
if(is_array($v)) {
|
if(is_array($v)) {
|
||||||
$length = count($v);
|
$length = count($v);
|
||||||
for($i = 0; $i < $length; ++$i) {
|
for($i = 0; $i < $length; ++$i) {
|
||||||
if(is_string($v[$i])) {
|
if(is_string($v[$i])) {
|
||||||
$url = jsonld_prepend_base($base, $v[$i]);
|
$url = jsonld_prepend_base($base, $v[$i]);
|
||||||
// replace w/@context if requested
|
// replace w/@context if requested
|
||||||
if($replace) {
|
if($replace) {
|
||||||
$ctx = $urls->{$url};
|
$ctx = $urls->{$url};
|
||||||
if(is_array($ctx)) {
|
if(is_array($ctx)) {
|
||||||
// add flattened context
|
// add flattened context
|
||||||
array_splice($v, $i, 1, $ctx);
|
array_splice($v, $i, 1, $ctx);
|
||||||
$i += count($ctx);
|
$i += count($ctx);
|
||||||
$length += count($ctx);
|
$length += count($ctx);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$v[$i] = $ctx;
|
$v[$i] = $ctx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// @context URL found
|
// @context URL found
|
||||||
else if(!property_exists($urls, $url)) {
|
else if(!property_exists($urls, $url)) {
|
||||||
$urls->{$url} = false;
|
$urls->{$url} = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// string @context
|
// string @context
|
||||||
else if(is_string($v)) {
|
else if(is_string($v)) {
|
||||||
$v = jsonld_prepend_base($base, $v);
|
$v = jsonld_prepend_base($base, $v);
|
||||||
// replace w/@context if requested
|
// replace w/@context if requested
|
||||||
if($replace) {
|
if($replace) {
|
||||||
$input->{$k} = $urls->{$v};
|
$input->{$k} = $urls->{$v};
|
||||||
}
|
}
|
||||||
// @context URL found
|
// @context URL found
|
||||||
else if(!property_exists($urls, $v)) {
|
else if(!property_exists($urls, $v)) {
|
||||||
$urls->{$v} = false;
|
$urls->{$v} = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves external @context URLs using the given URL client. Each
|
* Retrieves external @context URLs using the given URL client. Each
|
||||||
* instance of @context in the input that refers to a URL will be replaced
|
* instance of @context in the input that refers to a URL will be replaced
|
||||||
* with the JSON @context found at that URL.
|
* with the JSON @context found at that URL.
|
||||||
*
|
*
|
||||||
* @param mixed $input the JSON-LD input with possible contexts.
|
* @param mixed $input the JSON-LD input with possible contexts.
|
||||||
* @param stdClass $cycles an object for tracking context cycles.
|
* @param stdClass $cycles an object for tracking context cycles.
|
||||||
* @param callable $url_client(url) the URL client.
|
* @param callable $url_client(url) the URL client.
|
||||||
* @param base $base the base URL to resolve relative URLs against.
|
* @param base $base the base URL to resolve relative URLs against.
|
||||||
*
|
*
|
||||||
* @return mixed the result.
|
* @return mixed the result.
|
||||||
*/
|
*/
|
||||||
protected function _retrieveContextUrls(
|
protected function _retrieveContextUrls(
|
||||||
&$input, $cycles, $url_client, $base='') {
|
&$input, $cycles, $url_client, $base='') {
|
||||||
if(count(get_object_vars($cycles)) > self::MAX_CONTEXT_URLS) {
|
if(count(get_object_vars($cycles)) > self::MAX_CONTEXT_URLS) {
|
||||||
throw new JsonLdException(
|
throw new JsonLdException(
|
||||||
'Maximum number of @context URLs exceeded.',
|
'Maximum number of @context URLs exceeded.',
|
||||||
'jsonld.ContextUrlError', array('max' => self::MAX_CONTEXT_URLS));
|
'jsonld.ContextUrlError', array('max' => self::MAX_CONTEXT_URLS));
|
||||||
}
|
}
|
||||||
|
|
||||||
// for tracking the URLs to retrieve
|
// for tracking the URLs to retrieve
|
||||||
$urls = new stdClass();
|
$urls = new stdClass();
|
||||||
|
|
||||||
// find all URLs in the given input
|
// find all URLs in the given input
|
||||||
$this->_findContextUrls($input, $urls, false, $base);
|
$this->_findContextUrls($input, $urls, false, $base);
|
||||||
|
|
||||||
// queue all unretrieved URLs
|
// queue all unretrieved URLs
|
||||||
$queue = array();
|
$queue = array();
|
||||||
foreach($urls as $url => $ctx) {
|
foreach($urls as $url => $ctx) {
|
||||||
if($ctx === false) {
|
if($ctx === false) {
|
||||||
$queue[] = $url;
|
$queue[] = $url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve URLs in queue
|
// retrieve URLs in queue
|
||||||
foreach($queue as $url) {
|
foreach($queue as $url) {
|
||||||
// check for context URL cycle
|
// check for context URL cycle
|
||||||
if(property_exists($cycles, $url)) {
|
if(property_exists($cycles, $url)) {
|
||||||
throw new JsonLdException(
|
throw new JsonLdException(
|
||||||
'Cyclical @context URLs detected.',
|
'Cyclical @context URLs detected.',
|
||||||
'jsonld.ContextUrlError', array('url' => $url));
|
'jsonld.ContextUrlError', array('url' => $url));
|
||||||
}
|
}
|
||||||
$_cycles = self::copy($cycles);
|
$_cycles = self::copy($cycles);
|
||||||
$_cycles->{$url} = true;
|
$_cycles->{$url} = true;
|
||||||
|
|
||||||
// retrieve URL
|
// retrieve URL
|
||||||
$ctx = $url_client($url);
|
$ctx = $url_client($url);
|
||||||
|
|
||||||
// parse string context as JSON
|
// parse string context as JSON
|
||||||
if(is_string($ctx)) {
|
if(is_string($ctx)) {
|
||||||
$ctx = json_decode($ctx);
|
$ctx = json_decode($ctx);
|
||||||
switch(json_last_error()) {
|
switch(json_last_error()) {
|
||||||
case JSON_ERROR_NONE:
|
case JSON_ERROR_NONE:
|
||||||
break;
|
break;
|
||||||
case JSON_ERROR_DEPTH:
|
case JSON_ERROR_DEPTH:
|
||||||
throw new JsonLdException(
|
throw new JsonLdException(
|
||||||
'Could not parse JSON from URL; the maximum stack depth has ' .
|
'Could not parse JSON from URL; the maximum stack depth has ' .
|
||||||
'been exceeded.', 'jsonld.ParseError', array('url' => $url));
|
'been exceeded.', 'jsonld.ParseError', array('url' => $url));
|
||||||
case JSON_ERROR_STATE_MISMATCH:
|
case JSON_ERROR_STATE_MISMATCH:
|
||||||
throw new JsonLdException(
|
throw new JsonLdException(
|
||||||
'Could not parse JSON from URL; invalid or malformed JSON.',
|
'Could not parse JSON from URL; invalid or malformed JSON.',
|
||||||
'jsonld.ParseError', array('url' => $url));
|
'jsonld.ParseError', array('url' => $url));
|
||||||
case JSON_ERROR_CTRL_CHAR:
|
case JSON_ERROR_CTRL_CHAR:
|
||||||
case JSON_ERROR_SYNTAX:
|
case JSON_ERROR_SYNTAX:
|
||||||
throw new JsonLdException(
|
throw new JsonLdException(
|
||||||
'Could not parse JSON from URL; syntax error, malformed JSON.',
|
'Could not parse JSON from URL; syntax error, malformed JSON.',
|
||||||
'jsonld.ParseError', array('url' => $url));
|
'jsonld.ParseError', array('url' => $url));
|
||||||
case JSON_ERROR_UTF8:
|
case JSON_ERROR_UTF8:
|
||||||
throw new JsonLdException(
|
throw new JsonLdException(
|
||||||
'Could not parse JSON from URL; malformed UTF-8 characters.',
|
'Could not parse JSON from URL; malformed UTF-8 characters.',
|
||||||
'jsonld.ParseError', array('url' => $url));
|
'jsonld.ParseError', array('url' => $url));
|
||||||
default:
|
default:
|
||||||
throw new JsonLdException(
|
throw new JsonLdException(
|
||||||
'Could not parse JSON from URL; unknown error.',
|
'Could not parse JSON from URL; unknown error.',
|
||||||
'jsonld.ParseError', array('url' => $url));
|
'jsonld.ParseError', array('url' => $url));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// ensure ctx is an object
|
|
||||||
if(!is_object($ctx)) {
|
|
||||||
throw new JsonLdException(
|
|
||||||
'Derefencing a URL did not result in a valid JSON-LD object.',
|
|
||||||
'jsonld.InvalidUrl', array('url' => $url));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// use empty context if no @context key is present
|
// ensure ctx is an object
|
||||||
if(!property_exists($ctx, '@context')) {
|
if(!is_object($ctx)) {
|
||||||
$ctx = (object)array('@context' => new stdClass());
|
throw new JsonLdException(
|
||||||
|
'Derefencing a URL did not result in a valid JSON-LD object.',
|
||||||
|
'jsonld.InvalidUrl', array('url' => $url));
|
||||||
}
|
}
|
||||||
|
|
||||||
// recurse
|
// use empty context if no @context key is present
|
||||||
|
if(!property_exists($ctx, '@context')) {
|
||||||
|
$ctx = (object)array('@context' => new stdClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
// recurse
|
||||||
$this->_retrieveContextUrls($ctx, $_cycles, $url_client, $url);
|
$this->_retrieveContextUrls($ctx, $_cycles, $url_client, $url);
|
||||||
$urls->{$url} = $ctx->{'@context'};
|
$urls->{$url} = $ctx->{'@context'};
|
||||||
}
|
}
|
||||||
|
|
||||||
// replace all URLS in the input
|
// replace all URLS in the input
|
||||||
$this->_findContextUrls($input, $urls, true, $base);
|
$this->_findContextUrls($input, $urls, true, $base);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -4706,7 +4706,7 @@ class JsonLdProcessor {
|
||||||
// handle default language
|
// handle default language
|
||||||
$default_language = '@none';
|
$default_language = '@none';
|
||||||
if(property_exists($active_ctx, '@language')) {
|
if(property_exists($active_ctx, '@language')) {
|
||||||
$default_language = $active_ctx->{'@language'};
|
$default_language = $active_ctx->{'@language'};
|
||||||
}
|
}
|
||||||
|
|
||||||
// create term selections for each mapping in the context, ordered by
|
// create term selections for each mapping in the context, ordered by
|
||||||
|
|
@ -4720,13 +4720,13 @@ class JsonLdProcessor {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add term selection where it applies
|
// add term selection where it applies
|
||||||
if(property_exists($mapping, '@container')) {
|
if(property_exists($mapping, '@container')) {
|
||||||
$container = $mapping->{'@container'};
|
$container = $mapping->{'@container'};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$container = '@none';
|
$container = '@none';
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate over every IRI in the mapping
|
// iterate over every IRI in the mapping
|
||||||
$iris = $mapping->{'@id'};
|
$iris = $mapping->{'@id'};
|
||||||
|
|
@ -4844,73 +4844,73 @@ class JsonLdProcessor {
|
||||||
return $rval;
|
return $rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares two RDF statements for equality.
|
* Compares two RDF statements for equality.
|
||||||
*
|
*
|
||||||
* @param stdClass $s1 the first statement.
|
* @param stdClass $s1 the first statement.
|
||||||
* @param stdClass $s2 the second statement.
|
* @param stdClass $s2 the second statement.
|
||||||
*
|
*
|
||||||
* @return true if the statements are the same, false if not.
|
* @return true if the statements are the same, false if not.
|
||||||
*/
|
*/
|
||||||
protected static function _compareRdfStatements($s1, $s2) {
|
protected static function _compareRdfStatements($s1, $s2) {
|
||||||
if(is_string($s1) || is_string($s2)) {
|
if(is_string($s1) || is_string($s2)) {
|
||||||
return $s1 === $s2;
|
return $s1 === $s2;
|
||||||
}
|
}
|
||||||
|
|
||||||
$attrs = array('subject', 'property', 'object');
|
$attrs = array('subject', 'property', 'object');
|
||||||
foreach($attrs as $attr) {
|
foreach($attrs as $attr) {
|
||||||
if($s1->{$attr}->interfaceName !== $s2->{$attr}->interfaceName ||
|
if($s1->{$attr}->interfaceName !== $s2->{$attr}->interfaceName ||
|
||||||
$s1->{$attr}->nominalValue !== $s2->{$attr}->nominalValue) {
|
$s1->{$attr}->nominalValue !== $s2->{$attr}->nominalValue) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(property_exists($s1->object, 'language') !==
|
if(property_exists($s1->object, 'language') !==
|
||||||
property_exists($s1->object, 'language')) {
|
property_exists($s1->object, 'language')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(property_exists($s1->object, 'language')) {
|
if(property_exists($s1->object, 'language')) {
|
||||||
if($s1->object->language !== $s2->object->language) {
|
if($s1->object->language !== $s2->object->language) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(property_exists($s1->object, 'datatype') !==
|
if(property_exists($s1->object, 'datatype') !==
|
||||||
property_exists($s1->object, 'datatype')) {
|
property_exists($s1->object, 'datatype')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(property_exists($s1->object, 'datatype')) {
|
if(property_exists($s1->object, 'datatype')) {
|
||||||
if($s1->object->datatype->interfaceName !==
|
if($s1->object->datatype->interfaceName !==
|
||||||
$s2->object->datatype->interfaceName ||
|
$s2->object->datatype->interfaceName ||
|
||||||
$s1->object->datatype->nominalValue !==
|
$s1->object->datatype->nominalValue !==
|
||||||
$s2->object->datatype->nominalValue) {
|
$s2->object->datatype->nominalValue) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(property_exists($s1, 'name') !== property_exists($s1, 'name')) {
|
if(property_exists($s1, 'name') !== property_exists($s1, 'name')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(property_exists($s1, 'name')) {
|
if(property_exists($s1, 'name')) {
|
||||||
if($s1->name !== $s2->name) {
|
if($s1->name !== $s2->name) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Appends an RDF statement to the given array of statements if it is unique.
|
* Appends an RDF statement to the given array of statements if it is unique.
|
||||||
*
|
*
|
||||||
* @param array $statements the array to add to.
|
* @param array $statements the array to add to.
|
||||||
* @param stdClass $statement the statement to add.
|
* @param stdClass $statement the statement to add.
|
||||||
*/
|
*/
|
||||||
protected static function _appendUniqueRdfStatement(
|
protected static function _appendUniqueRdfStatement(
|
||||||
&$statements, $statement) {
|
&$statements, $statement) {
|
||||||
foreach($statements as $s) {
|
foreach($statements as $s) {
|
||||||
if(self::_compareRdfStatements($s, $statement)) {
|
if(self::_compareRdfStatements($s, $statement)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$statements[] = $statement;
|
$statements[] = $statement;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether or not the given value is a keyword.
|
* Returns whether or not the given value is a keyword.
|
||||||
|
|
@ -5125,9 +5125,9 @@ class JsonLdProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// register the N-Quads RDF parser
|
// register the N-Quads RDF parser
|
||||||
jsonld_register_rdf_parser(
|
jsonld_register_rdf_parser(
|
||||||
'application/nquads', 'JsonLdProcessor::parseNQuads');
|
'application/nquads', 'JsonLdProcessor::parseNQuads');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A JSON-LD Exception.
|
* A JSON-LD Exception.
|
||||||
|
|
@ -5301,66 +5301,66 @@ class Permutator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An ActiveContextCache caches active contexts so they can be reused without
|
* An ActiveContextCache caches active contexts so they can be reused without
|
||||||
* the overhead of recomputing them.
|
* the overhead of recomputing them.
|
||||||
*/
|
*/
|
||||||
class ActiveContextCache {
|
class ActiveContextCache {
|
||||||
/**
|
/**
|
||||||
* Constructs a new ActiveContextCache.
|
* Constructs a new ActiveContextCache.
|
||||||
*
|
*
|
||||||
* @param int size the maximum size of the cache, defaults to 100.
|
* @param int size the maximum size of the cache, defaults to 100.
|
||||||
*/
|
*/
|
||||||
public function __construct($size=100) {
|
public function __construct($size=100) {
|
||||||
$this->order = array();
|
$this->order = array();
|
||||||
$this->cache = new stdClass();
|
$this->cache = new stdClass();
|
||||||
$this->size = $size;
|
$this->size = $size;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets an active context from the cache based on the current active
|
|
||||||
* context and the new local context.
|
|
||||||
*
|
|
||||||
* @param stdClass $active_ctx the current active context.
|
|
||||||
* @param stdClass $local_ctx the new local context.
|
|
||||||
*
|
|
||||||
* @return mixed a shared copy of the cached active context or null.
|
|
||||||
*/
|
|
||||||
public function get($active_ctx, $local_ctx) {
|
|
||||||
$key1 = serialize($active_ctx);
|
|
||||||
$key2 = serialize($local_ctx);
|
|
||||||
if(property_exists($this->cache, $key1)) {
|
|
||||||
$level1 = $this->cache->{$key1};
|
|
||||||
if(property_exists($level1, $key2)) {
|
|
||||||
// get shareable copy of cached active context
|
|
||||||
return JsonLdProcessor::_shareActiveContext($level1->{$key2});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an active context in the cache based on the previous active
|
* Gets an active context from the cache based on the current active
|
||||||
* context and the just-processed local context.
|
* context and the new local context.
|
||||||
*
|
*
|
||||||
* @param stdClass $active_ctx the previous active context.
|
* @param stdClass $active_ctx the current active context.
|
||||||
|
* @param stdClass $local_ctx the new local context.
|
||||||
|
*
|
||||||
|
* @return mixed a shared copy of the cached active context or null.
|
||||||
|
*/
|
||||||
|
public function get($active_ctx, $local_ctx) {
|
||||||
|
$key1 = serialize($active_ctx);
|
||||||
|
$key2 = serialize($local_ctx);
|
||||||
|
if(property_exists($this->cache, $key1)) {
|
||||||
|
$level1 = $this->cache->{$key1};
|
||||||
|
if(property_exists($level1, $key2)) {
|
||||||
|
// get shareable copy of cached active context
|
||||||
|
return JsonLdProcessor::_shareActiveContext($level1->{$key2});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets an active context in the cache based on the previous active
|
||||||
|
* context and the just-processed local context.
|
||||||
|
*
|
||||||
|
* @param stdClass $active_ctx the previous active context.
|
||||||
* @param stdClass $local_ctx the just-processed local context.
|
* @param stdClass $local_ctx the just-processed local context.
|
||||||
* @param stdClass $result the resulting active context.
|
* @param stdClass $result the resulting active context.
|
||||||
*/
|
*/
|
||||||
public function set($active_ctx, $local_ctx, $result) {
|
public function set($active_ctx, $local_ctx, $result) {
|
||||||
if(count($this->order) === $this->size) {
|
if(count($this->order) === $this->size) {
|
||||||
$entry = array_shift($this->order);
|
$entry = array_shift($this->order);
|
||||||
unset($this->cache->{$entry->activeCtx}->{$entry->localCtx});
|
unset($this->cache->{$entry->activeCtx}->{$entry->localCtx});
|
||||||
}
|
}
|
||||||
$key1 = serialize($active_ctx);
|
$key1 = serialize($active_ctx);
|
||||||
$key2 = serialize($local_ctx);
|
$key2 = serialize($local_ctx);
|
||||||
$this->order[] = (object)array(
|
$this->order[] = (object)array(
|
||||||
'activeCtx' => $key1, 'localCtx' => $key2);
|
'activeCtx' => $key1, 'localCtx' => $key2);
|
||||||
if(!property_exists($this->cache, $key1)) {
|
if(!property_exists($this->cache, $key1)) {
|
||||||
$this->cache->{$key1} = new stdClass();
|
$this->cache->{$key1} = new stdClass();
|
||||||
}
|
}
|
||||||
$this->cache->{$key1}->{$key2} = $result;
|
$this->cache->{$key1}->{$key2} = $result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* end of file, omit ?> */
|
/* end of file, omit ?> */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue