Example #1
0
 /**
  * Loads a remote document or context
  *
  * @param string $url The URL of the document to load.
  *
  * @return RemoteDocument The remote document.
  *
  * @throws JsonLdException If loading the document failed.
  */
 public static function loadDocument($url)
 {
     // if input looks like a file, try to retrieve it
     $input = trim($url);
     if (false == (isset($input[0]) && "{" === $input[0] || "[" === $input[0])) {
         $remoteDocument = new RemoteDocument($url);
         $streamContextOptions = array('method' => 'GET', 'header' => "Accept: application/ld+json, application/json; q=0.9, */*; q=0.1\r\n", 'timeout' => Processor::REMOTE_TIMEOUT);
         $context = stream_context_create(array('http' => $streamContextOptions, 'https' => $streamContextOptions));
         $httpHeadersOffset = 0;
         stream_context_set_params($context, array('notification' => function ($code, $severity, $msg, $msgCode, $bytesTx, $bytesMax) use(&$remoteDocument, &$http_response_header, &$httpHeadersOffset) {
             if ($code === STREAM_NOTIFY_MIME_TYPE_IS) {
                 $remoteDocument->mediaType = $msg;
             } elseif ($code === STREAM_NOTIFY_REDIRECTED) {
                 $remoteDocument->documentUrl = $msg;
                 $remoteDocument->mediaType = null;
                 $httpHeadersOffset = count($http_response_header);
             }
         }));
         if (false === ($input = @file_get_contents($url, false, $context))) {
             throw new JsonLdException(JsonLdException::LOADING_DOCUMENT_FAILED, sprintf('Unable to load the remote document "%s".', $url), $http_response_header);
         }
         // Extract HTTP Link headers
         $linkHeaderValues = array();
         for ($i = count($http_response_header) - 1; $i > $httpHeadersOffset; $i--) {
             if (0 === substr_compare($http_response_header[$i], 'Link:', 0, 5, true)) {
                 $value = substr($http_response_header[$i], 5);
                 $linkHeaderValues[] = $value;
             }
         }
         $linkHeaderValues = self::parseContextLinkHeaders($linkHeaderValues, new IRI($url));
         if (count($linkHeaderValues) === 1) {
             $remoteDocument->contextUrl = reset($linkHeaderValues);
         } elseif (count($linkHeaderValues) > 1) {
             throw new JsonLdException(JsonLdException::MULTIPLE_CONTEXT_LINK_HEADERS, 'Found multiple contexts in HTTP Link headers', $http_response_header);
         }
         // If we got a media type, we verify it
         if ($remoteDocument->mediaType) {
             // Drop any media type parameters such as profiles
             if (false !== ($pos = strpos($remoteDocument->mediaType, ';'))) {
                 $remoteDocument->mediaType = substr($remoteDocument->mediaType, 0, $pos);
             }
             $remoteDocument->mediaType = trim($remoteDocument->mediaType);
             if ('application/ld+json' === $remoteDocument->mediaType) {
                 $remoteDocument->contextUrl = null;
             } elseif ('application/json' !== $remoteDocument->mediaType && 0 !== substr_compare($remoteDocument->mediaType, '+json', -5)) {
                 throw new JsonLdException(JsonLdException::LOADING_DOCUMENT_FAILED, 'Invalid media type', $remoteDocument->mediaType);
             }
         }
         $remoteDocument->document = Processor::parse($input);
         return $remoteDocument;
     }
     return new RemoteDocument($url, Processor::parse($input));
 }
Example #2
0
 /**
  * Tests the serialization of graphs
  */
 public function testSerializeGraph()
 {
     // This is the expanded and flattened version of the test document
     // (the blank node labels have been renamed from _:t... to _:b...)
     $expected = Processor::loadDocument('[{
            "@id": "_:b0",
            "http://vocab.com/nested": [{
               "@value": "1.1"
            }]
         }, {
            "@id": "_:b1",
            "http://vocab.com/nested": [{
               "@value": "2.1"
            }]
         }, {
            "@id": "_:b2",
            "http://vocab.com/nested": [{
               "@value": "2.2"
            }]
         }, {
            "@id": "_:b3",
            "http://vocab.com/nested": [{
               "@value": "3.1"
            }]
         }, {
            "@id": "http://example.com/node/1",
            "@type": ["http://vocab.com/type/node"],
            "http://vocab.com/contains": [{
               "@id": "_:b0"
            }],
            "http://vocab.com/link": [{
               "@id": "http://example.com/node/2"
            }],
            "http://vocab.com/name": [{
               "@value": "1"
            }]
         }, {
            "@id": "http://example.com/node/2",
            "@type": ["http://vocab.com/type/nodeWithAliases"],
            "http://vocab.com/aliases": [{
               "@value": "node2"
            }, {
               "@value": 2,
               "@type": "http://www.w3.org/2001/XMLSchema#integer"
            }],
            "http://vocab.com/contains": [{
               "@id": "_:b1"
            }, {
               "@id": "_:b2"
            }],
            "http://vocab.com/lang": [{
               "@language": "en",
               "@value": "language-tagged string"
            }],
            "http://vocab.com/link": [{
               "@id": "http://example.com/node/3"
            }],
            "http://vocab.com/name": [{
               "@value": "2"
            }],
            "http://vocab.com/typed": [{
               "@type": "http://vocab.com/type/datatype",
               "@value": "typed value"
            }]
         }, {
            "@id": "http://example.com/node/3",
            "@type": ["http://vocab.com/type/node"],
            "http://vocab.com/contains": [{
               "@id": "_:b3"
            }],
            "http://vocab.com/lang": [{
               "@language": "en",
               "@value": "language-tagged string: en"
            }, {
               "@language": "de",
               "@value": "language-tagged string: de"
            }],
            "http://vocab.com/link": [{
               "@id": "http://example.com/node/1"
            }],
            "http://vocab.com/name": [{
               "@value": "3"
            }],
            "http://vocab.com/typed": [{
               "@type": "http://vocab.com/type/datatype",
               "@value": "typed value"
            }, {
               "@language": "ex:/type/otherDataType",
               "@value": "typed value"
            }, {
               "@language": "ex:/type/datatype",
               "@value": "typed value"
            }]
         }, {
            "@id": "http://vocab.com/type/node"
         }, {
            "@id": "http://vocab.com/type/nodeWithAliases"
         }]');
     $this->assertEquals($expected, $this->graph->toJsonLd(false), 'Serialize graph');
 }
Example #3
0
 /**
  * Frames a JSON-LD document according a supplied frame
  *
  * @param array|object $element A JSON-LD element to be framed.
  * @param mixed        $frame   The frame.
  *
  * @return array $result The framed element in expanded form.
  *
  * @throws JsonLdException
  */
 public function frame($element, $frame)
 {
     if (false === is_array($frame) || 1 !== count($frame) || false === is_object($frame[0])) {
         throw new JsonLdException(JsonLdException::UNSPECIFIED, 'The frame is invalid. It must be a single object.', $frame);
     }
     $frame = $frame[0];
     $options = new Object();
     $options->{'@embed'} = true;
     $options->{'@embedChildren'} = true;
     // TODO Change this as soon as the tests haven been updated
     foreach (self::$framingKeywords as $keyword) {
         if (property_exists($frame, $keyword)) {
             $options->{$keyword} = $frame->{$keyword};
             unset($frame->{$keyword});
         } elseif (false === property_exists($options, $keyword)) {
             $options->{$keyword} = false;
         }
     }
     $procOptions = new Object();
     $procOptions->base = (string) $this->baseIri;
     // TODO Check which base IRI to use
     $procOptions->compactArrays = $this->compactArrays;
     $procOptions->optimize = $this->optimize;
     $procOptions->useNativeTypes = $this->useNativeTypes;
     $procOptions->useRdfType = $this->useRdfType;
     $procOptions->produceGeneralizedRdf = $this->generalizedRdf;
     $procOptions->documentFactory = $this->documentFactory;
     $processor = new Processor($procOptions);
     $graph = JsonLD::MERGED_GRAPH;
     if (property_exists($frame, '@graph')) {
         $graph = JsonLD::DEFAULT_GRAPH;
     }
     $nodeMap = new Object();
     $nodeMap->{'-' . $graph} = new Object();
     $processor->generateNodeMap($nodeMap, $element, $graph);
     // Sort the node map to ensure a deterministic output
     // TODO Move this to a separate function as basically the same is done in flatten()?
     $nodeMap = (array) $nodeMap;
     foreach ($nodeMap as &$nodes) {
         $nodes = (array) $nodes;
         ksort($nodes);
         $nodes = (object) $nodes;
     }
     $nodeMap = (object) $nodeMap;
     unset($processor);
     $result = array();
     foreach ($nodeMap->{'-' . $graph} as $node) {
         $this->nodeMatchesFrame($node, $frame, $options, $nodeMap, $graph, $result);
     }
     return $result;
 }
Example #4
0
 /**
  * Merge the passed options with the options' default values.
  *
  * @param null|array|object $options The options.
  *
  * @return object The merged options.
  */
 private static function mergeOptions($options)
 {
     $result = (object) array('base' => null, 'expandContext' => null, 'compactArrays' => true, 'optimize' => false, 'graph' => null, 'useNativeTypes' => false, 'useRdfType' => false, 'produceGeneralizedRdf' => false, 'documentFactory' => null);
     if (is_array($options) || is_object($options)) {
         $options = (object) $options;
         if (isset($options->{'base'})) {
             if (is_string($options->{'base'})) {
                 $result->base = new IRI($options->{'base'});
             } elseif ($options->{'base'} instanceof IRI && $options->{'base'}->isAbsolute()) {
                 $result->base = clone $options->{'base'};
             } else {
                 throw \InvalidArgumentException('The "base" option must be set to null or an absolute IRI.');
             }
         }
         if (property_exists($options, 'expandContext')) {
             if (is_string($options->expandContext)) {
                 $result->expandContext = Processor::loadDocument($options->expandContext);
             } elseif (is_object($options->expandContext)) {
                 $result->expandContext = $options->expandContext;
             }
             if (is_object($result->expandContext) && property_exists($result->expandContext, '@context')) {
                 $result->expandContext = $result->expandContext->{'@context'};
             }
         }
         if (property_exists($options, 'compactArrays') && is_bool($options->compactArrays)) {
             $result->compactArrays = $options->compactArrays;
         }
         if (property_exists($options, 'optimize') && is_bool($options->optimize)) {
             $result->optimize = $options->optimize;
         }
         if (property_exists($options, 'graph') && is_string($options->graph)) {
             $result->graph = $options->graph;
         }
         if (property_exists($options, 'useNativeTypes') && is_bool($options->useNativeTypes)) {
             $result->useNativeTypes = $options->useNativeTypes;
         }
         if (property_exists($options, 'useRdfType') && is_bool($options->useRdfType)) {
             $result->useRdfType = $options->useRdfType;
         }
         if (property_exists($options, 'produceGeneralizedRdf') && is_bool($options->produceGeneralizedRdf)) {
             $result->produceGeneralizedRdf = $options->produceGeneralizedRdf;
         }
         if (property_exists($options, 'documentFactory') && $options->documentFactory instanceof DocumentFactoryInterface) {
             $result->documentFactory = $options->documentFactory;
         }
     }
     return $result;
 }