Esempio n. 1
0
 protected function open()
 {
     $this->graph = new Graph();
     $rdfa_parser = new RdfaParser();
     $json_parser = new JsonLd();
     \EasyRdf\RdfNamespace::set('dcat', 'http://www.w3.org/ns/dcat#');
     \EasyRdf\RdfNamespace::set('lbld', 'http://decisions.data.vlaanderen.be/ns#');
     $data = file_get_contents($this->extractor->uri);
     // Assume we have an rdfa document to begin with
     $rdfa_parser->parse($this->graph, $data, 'rdfa', $this->extractor->base_uri);
     // Check if we have properties we need to include into the current graph
     $properties = explode(',', $this->extractor->follow_properties);
     foreach ($this->graph->resources() as $resource) {
         foreach ($properties as $property) {
             $resolve_resources = $resource->allResources($property);
             if (!empty($resolve_resources)) {
                 foreach ($resolve_resources as $resolve_resource) {
                     $data = file_get_contents($resolve_resource->getUri());
                     // Parse any rdfa data in the document into the existing graph
                     $this->graph->parse($data, 'rdfa', $resolve_resource->getUri());
                     $json = $this->parseJsonldSnippet($data);
                     if (!empty($json)) {
                         try {
                             $this->graph->parse($json, 'jsonld', $resolve_resource->getUri());
                         } catch (\Exception $ex) {
                             \Log::error("We could not parse json from the data, the data was:" . $json);
                         }
                     }
                 }
             }
         }
     }
     // We only return the graph once as a full datastructure
     $this->has_next = true;
 }
Esempio n. 2
0
 public static function getBody($dataObj)
 {
     if ($dataObj->is_semantic) {
         // Check if a configuration is given
         $conf = array();
         if (!empty($dataObj->semantic->conf)) {
             $conf = $dataObj->semantic->conf;
             foreach ($conf['ns'] as $prefix => $uri) {
                 RdfNamespace::set($prefix, $uri);
             }
         }
         // Add the configured ontology prefixes
         $ontologies = \App::make('Tdt\\Core\\Repositories\\Interfaces\\OntologyRepositoryInterface');
         $context = array();
         // Only add the common namespaces
         $namespaces = array('hydra', 'rdf', 'rdfs', 'foaf', 'void', 'xsd', 'skos', 'xs');
         foreach ($namespaces as $ns) {
             $namespace = $ontologies->getByPrefix($ns);
             if (!empty($namespace)) {
                 $context[$ns] = $namespace['uri'];
             }
         }
         $output = $dataObj->data->serialise('jsonld');
         // Next, encode the context as JSON
         $jsonContext = json_encode($context);
         // Compact the JsonLD by using @context -> Needs tweaking can only return the
         // URI spaces that are used in the document.
         $compacted = JsonLD::compact($output, $jsonContext);
         // Print the resulting JSON-LD!
         return JsonLD::toString($compacted, true);
     } else {
         \App::abort(400, "The data is not a semantically linked document, a linked data JSON representation is not possible.");
     }
 }
 public function __construct($endpoint, $namespaces)
 {
     $this->endpoint = $endpoint;
     $this->namespaces = $namespaces;
     foreach ($namespaces as $namespace => $uri) {
         \EasyRdf\RdfNamespace::set($namespace, $uri);
     }
 }
Esempio n. 4
0
 /**
  * @param $types
  * @return array|null
  */
 public function getMostAccurateType($types, $knowTypesForExternService = array())
 {
     // filter types to have only types filiation defined with subClassOf annotation
     $definedOntoTypes = array();
     foreach ($types as $type) {
         $type = (string) $type;
         if ($type && !empty($type)) {
             $shortenType = RdfNamespace::shorten($type);
             if (isset($this->rdfFiliation[$shortenType])) {
                 $definedOntoTypes[] = $shortenType;
             }
         }
     }
     $arrayAccurateOnes = array();
     if (count($definedOntoTypes) == 0) {
         return null;
     } else {
         if (count($definedOntoTypes) == 1) {
             $arrayAccurateOnes = $definedOntoTypes;
         } else {
             // try to find the most accurate type
             foreach ($definedOntoTypes as $currentType) {
                 $mostAccurate = true;
                 if (isset($this->rdfFiliation[$currentType]['parentClassOf'])) {
                     $subClassTypes = $this->rdfFiliation[$currentType]['parentClassOf'];
                     // in class children types, look if one of them is defined with subClassOf annotation
                     foreach ($definedOntoTypes as $type) {
                         if (in_array($type, $subClassTypes)) {
                             $mostAccurate = false;
                             break;
                         }
                     }
                 }
                 if ($mostAccurate) {
                     $arrayAccurateOnes[] = $currentType;
                 }
             }
         }
     }
     if (!empty($knowTypesForExternService)) {
         return $this->findMostAccurateTypesInKnowTypesByExternalService($arrayAccurateOnes, $knowTypesForExternService);
     }
     return $arrayAccurateOnes;
 }
Esempio n. 5
0
 /**
  * Create the DCAT document of the published (non-draft) resources
  *
  * @return mixed \Data object with a graph of DCAT information
  */
 private function createDcat()
 {
     $ns = $this->dcat->getNamespaces();
     foreach ($ns as $prefix => $uri) {
         RdfNamespace::set($prefix, $uri);
     }
     // If limit is empty, provide a custom page size for the DCAT document
     $limit = \Input::get('limit');
     if (empty($limit)) {
         \Input::merge(array('limit' => 100));
     }
     // Apply paging when fetching the definitions
     list($limit, $offset) = Pager::calculateLimitAndOffset();
     $definition_count = $this->definitions->countPublished();
     $definitions = $this->definitions->getAllPublished($limit, $offset);
     $oldest = $this->definitions->getOldest();
     $describedDefinitions = array();
     // Add the source type description to the definition
     foreach ($definitions as $definition) {
         $definition = array_merge($definition, $this->definitions->getFullDescription($definition['collection_uri'] . '/' . $definition['resource_name']));
         array_push($describedDefinitions, $definition);
     }
     $graph = $this->dcat->getDcatDocument($describedDefinitions, $oldest);
     // Return the dcat feed in our internal data object
     $data_result = new Data();
     $data_result->data = $graph;
     $data_result->is_semantic = true;
     $data_result->paging = Pager::calculatePagingHeaders($limit, $offset, $definition_count);
     // Add the semantic configuration for the ARC graph
     $data_result->semantic = new \stdClass();
     $data_result->semantic->conf = array('ns' => $ns);
     $data_result->definition = [];
     $data_result->definition['resource_name'] = 'dcat';
     $data_result->definition['collection_uri'] = 'info';
     $data_result->definition['source_type'] = 'DCAT';
     return $data_result;
 }
Esempio n. 6
0
 protected function open()
 {
     // Perform XLST
     $xsl_url = "https://webgate.ec.europa.eu/CITnet/stash/projects/ODCKAN/repos/iso-19139-to-dcat-ap/browse/iso-19139-to-dcat-ap.xsl?raw";
     $proc = null;
     try {
         $xml = new DOMDocument();
         $xml->load($this->extractor->uri);
         $xsl = new DOMDocument();
         $xsl->load($xsl_url);
         $proc = new XSLTProcessor();
         $proc->importStyleSheet($xsl);
     } catch (\ErrorException $ex) {
         $this->log('Something went wrong: ' . $ex->getMessage());
         die;
     }
     $dcat_document = $proc->transformToXML($xml);
     \EasyRdf\RdfNamespace::set('locn', 'http://www.w3.org/ns/locn#');
     // Parse the dcat graph
     $graph = new Graph();
     $rdf_parser = new RdfXml();
     $rdf_parser->parse($graph, $dcat_document, 'rdfxml', 'http://foo');
     $this->datasets = $graph->allOfType('dcat:Dataset');
 }
 private function sparqlRetrieveTriplesForNotation($notation)
 {
     // alternative query (the fuseki's query is the same except that # must be encoded as %23 or it will be understood as eof
     //$query = "prefix skos: <http://www.w3.org/2004/02/skos/core#> select ?s ?p  ?o where {?s  skos:notation '" . $notation .  "' . }";
     \EasyRdf\RdfNamespace::set('skos', 'http://www.w3.org/2004/02/skos/core#');
     $query = "select ?s ?p  ?o where {?s  skos:notation '" . $notation . "' . }";
     $sparqlClient = new \EasyRdf\Sparql\Client(BASE_URI_ . ':3030/openskos/query');
     $result = $sparqlClient->query($query);
     return $result;
 }
Esempio n. 8
0
 /**
  * @ignore
  */
 protected function serialisePrefixes()
 {
     $turtle = '';
     foreach ($this->prefixes as $prefix => $count) {
         $url = RdfNamespace::get($prefix);
         $turtle .= "@prefix {$prefix}: <{$url}> .\n";
     }
     return $turtle;
 }
Esempio n. 9
0
 /**
  * Retrieve a Data object identified by $uri
  *
  * @param string $uri The identifier that identifies a resource
  *
  * @return \Response
  */
 public function get($uri)
 {
     // Check permissions
     Auth::requirePermissions('dataset.view');
     // Split for an (optional) extension
     list($uri, $extension) = self::processURI($uri);
     $extension = strtolower($extension);
     // Check for caching
     // Based on: URI / Rest parameters / Query parameters / Paging headers
     $cache_string = $uri;
     list($limit, $offset) = Pager::calculateLimitAndOffset();
     $cache_string .= '/limit=' . $limit . 'offset=' . $offset;
     $omit = ['limit', 'offset', 'page', 'page_size'];
     $query_string_params = \Input::get();
     foreach ($query_string_params as $key => $val) {
         if (in_array($key, $omit)) {
             unset($query_string_params[$key]);
         }
     }
     $cache_string .= http_build_query($query_string_params);
     $cache_string = sha1($cache_string);
     if (Cache::has($cache_string)) {
         return ContentNegotiator::getResponse(Cache::get($cache_string), $extension);
     } else {
         // Get definition
         $definition = $this->definition->getByIdentifier($uri);
         if ($definition) {
             // Get source definition
             $source_definition = $this->definition->getDefinitionSource($definition['source_id'], $definition['source_type']);
             if ($source_definition) {
                 $source_type = $source_definition['type'];
                 // KML can be formatted into different formats
                 if ($source_definition['type'] == 'XML' && $source_definition['geo_formatted'] == 1) {
                     $source_type == 'kml';
                     $source_definition['type'] = 'KML';
                 }
                 // Create the right datacontroller
                 $controller_class = 'Tdt\\Core\\DataControllers\\' . $source_type . 'Controller';
                 $data_controller = \App::make($controller_class);
                 // Get REST parameters
                 $uri_segments = explode('/', $uri);
                 $definition_segments = explode('/', $definition['collection_uri']);
                 array_push($definition_segments, $definition['resource_name']);
                 $rest_parameters = array_diff($uri_segments, $definition_segments);
                 $rest_parameters = array_values($rest_parameters);
                 $throttle_response = $this->applyThrottle($definition);
                 if (!empty($throttle_response)) {
                     return $throttle_response;
                 }
                 // Retrieve dataobject from datacontroller
                 $data = $data_controller->readData($source_definition, $rest_parameters);
                 // If the source type is XML, just return the XML contents, don't transform
                 if (strtolower($source_type) == 'xml' && $extension == 'xml') {
                     return $this->createXMLResponse($data->data);
                 } elseif (strtolower($source_type) == 'xml' && $extension == 'kml' && $data->geo_formatted) {
                     return $this->createXMLResponse($data->data);
                 } elseif (!$data->is_semantic && $extension == 'xml' && $source_type != 'xml') {
                     \App::abort(406, "The requested format for the datasource is not available.");
                 } elseif (strtolower($source_type) == 'xml' && !$data->geo_formatted && !empty($extension) && $extension != 'xml') {
                     \App::abort(406, "The requested format for the datasource is not available.");
                 } elseif (strtolower($source_type) == 'xml' && $data->geo_formatted && !empty($extension) && !in_array($extension, $data->preferred_formats)) {
                     \App::abort(406, "The requested format for the datasource is not available.");
                 }
                 $data->rest_parameters = $rest_parameters;
                 // REST filtering
                 if ($source_type != 'INSTALLED' && count($data->rest_parameters) > 0) {
                     $data->data = self::applyRestFilter($data->data, $data->rest_parameters);
                 }
                 // Semantic paging with the hydra voc
                 if ($data->is_semantic && !empty($data->paging)) {
                     RdfNamespace::set('hydra', 'http://www.w3.org/ns/hydra/core#');
                     $graph = $data->data;
                     $url = \URL::to($definition['collection_uri'] . '/' . $definition['resource_name']);
                     $request_url = \Request::url();
                     $graph->addResource($request_url, 'void:subset', $url);
                     foreach ($data->paging as $key => $val) {
                         $paged_url = $request_url . '?offset=' . $val[0] . '&limit=' . $val[1] . Pager::buildQuerystring();
                         switch ($key) {
                             case 'next':
                                 $graph->addResource($request_url, 'hydra:nextPage', $paged_url);
                                 break;
                             case 'previous':
                                 $graph->addResource($request_url, 'hydra:previousPage', $paged_url);
                                 break;
                             case 'last':
                                 $graph->addResource($request_url, 'hydra:lastPage', $paged_url);
                                 break;
                             case 'first':
                                 $graph->addResource($request_url, 'hydra:firstPage', $paged_url);
                                 break;
                         }
                     }
                     $graph->addResource($url, 'a', 'dcat:Dataset');
                     $title = null;
                     if (!empty($definition['title'])) {
                         $title = $definition['title'];
                     } else {
                         $title = $definition['collection_uri'] . '/' . $definition['resource_name'];
                     }
                     $graph->addLiteral($url, 'dc:title', $title);
                     $graph->addLiteral($url, 'dc:description', $source_definition['description']);
                     $graph->addResource($url, 'dcat:distribution', $url . '.json');
                     $data->data = $graph;
                 }
                 // Add definition to the object
                 $data->definition = $definition;
                 // Add source definition to the object
                 $data->source_definition = $source_definition;
                 // Add the available, supported formats to the object
                 $format_helper = new FormatHelper();
                 $data->formats = $format_helper->getAvailableFormats($data);
                 // Store in cache
                 if (!empty($definition['cache_minutes'])) {
                     Cache::put($cache_string, $data, $definition['cache_minutes']);
                 }
                 // Return the formatted response with content negotiation
                 return ContentNegotiator::getResponse($data, $extension);
             } else {
                 \App::abort(404, "Source for the definition could not be found.");
             }
         } else {
             // Coulnd't find a definition, but it might be a collection
             $resources = $this->definition->getByCollection($uri);
             if (count($resources) > 0) {
                 $data = new Data();
                 $data->data = new \stdClass();
                 $data->data->datasets = array();
                 $data->data->collections = array();
                 foreach ($resources as $res) {
                     // Check if it's a subcollection or a dataset
                     $collection_uri = rtrim($res['collection_uri'], '/');
                     if ($collection_uri == $uri) {
                         array_push($data->data->datasets, \URL::to($collection_uri . '/' . $res['resource_name']));
                     } else {
                         // Push the subcollection if it's not already in the array
                         if (!in_array(\URL::to($collection_uri), $data->data->collections)) {
                             array_push($data->data->collections, \URL::to($collection_uri));
                         }
                     }
                 }
                 // Fake a definition
                 $data->definition = new \Definition();
                 $uri_array = explode('/', $uri);
                 $last_chunk = array_pop($uri_array);
                 $data->definition->collection_uri = join('/', $uri_array);
                 $data->definition->resource_name = $last_chunk;
                 // Return the formatted response with content negotiation
                 return ContentNegotiator::getResponse($data, $extension);
             } else {
                 \App::abort(404, "The dataset or collection you were looking for could not be found (URI: {$uri}).");
             }
         }
     }
 }
Esempio n. 10
0
 /**
  * Parses qnames and boolean values, which have equivalent starting
  * characters.
  * @ignore
  */
 protected function parseQNameOrBoolean()
 {
     // First character should be a ':' or a letter
     $c = $this->read();
     if ($c == -1) {
         throw new Exception("Turtle Parse Error: unexpected end of file while readying value", $this->line, $this->column);
     }
     if ($c != ':' && !self::isPrefixStartChar($c)) {
         throw new Exception("Turtle Parse Error: expected a ':' or a letter, found '{$c}'", $this->line, $this->column);
     }
     $namespace = null;
     if ($c == ':') {
         // qname using default namespace
         if (isset($this->namespaces[''])) {
             $namespace = $this->namespaces[''];
         } else {
             throw new Exception("Turtle Parse Error: default namespace used but not defined", $this->line, $this->column);
         }
     } else {
         // $c is the first letter of the prefix
         $prefix = $c;
         $c = $this->read();
         while (self::isPrefixChar($c)) {
             $prefix .= $c;
             $c = $this->read();
         }
         if ($c != ':') {
             // prefix may actually be a boolean value
             $value = $prefix;
             if ($value == "true" || $value == "false") {
                 return array('type' => 'literal', 'value' => $value, 'datatype' => RdfNamespace::get('xsd') . 'boolean');
             }
         }
         $this->verifyCharacterOrFail($c, ":");
         if (isset($this->namespaces[$prefix])) {
             $namespace = $this->namespaces[$prefix];
         } else {
             throw new Exception("Turtle Parse Error: namespace prefix '{$prefix}' used but not defined", $this->line, $this->column);
         }
     }
     // $c == ':', read optional local name
     $localName = '';
     $c = $this->read();
     if (self::isNameStartChar($c)) {
         if ($c == '\\') {
             $localName .= $this->readLocalEscapedChar();
         } else {
             $localName .= $c;
         }
         $c = $this->read();
         while (self::isNameChar($c)) {
             if ($c == '\\') {
                 $localName .= $this->readLocalEscapedChar();
             } else {
                 $localName .= $c;
             }
             $c = $this->read();
         }
     }
     // Unread last character
     $this->unread($c);
     // Note: namespace has already been resolved
     return array('type' => 'uri', 'value' => $namespace . $localName);
 }
Esempio n. 11
0
 /**
  * Adds missing prefix-definitions to the query
  *
  * Overriding classes may execute arbitrary query-alteration here
  *
  * @param string $query
  * @return string
  */
 protected function preprocessQuery($query)
 {
     // Check for undefined prefixes
     $prefixes = '';
     foreach (RdfNamespace::namespaces() as $prefix => $uri) {
         if (strpos($query, "{$prefix}:") !== false and strpos($query, "PREFIX {$prefix}:") === false) {
             $prefixes .= "PREFIX {$prefix}: <{$uri}>\n";
         }
     }
     return $prefixes . $query;
 }
Esempio n. 12
0
 protected function open()
 {
     \EasyRdf\RdfNamespace::set('locn', 'http://www.w3.org/ns/locn#');
     $graph = Graph::newAndLoad($this->extractor->uri, $this->extractor->format);
     $this->datasets = $graph->allOfType('dcat:Dataset');
 }
    public function subscribe($agentURI, $digestSubscriptionURI, $period)
    {
        $index = 1;
        $query = <<<INSERT
            <{$agentURI}> tal:subscriptionApplied _:b{$index} .
            _:b{$index} tal:subscriptionType <{$digestSubscriptionURI}> .
            _:b{$index} tal:subscriptionPeriod {$period} .
INSERT;
        $graphIRI = 'tal:SubscriptionGraph';
        $graphURI = RdfNamespace::expand($graphIRI);
        echo $query;
        try {
            $this->endpoint->insert($query, $graphURI);
        } catch (\EasyRdf\Http\Exception $e) {
            echo $e->getBody();
        }
    }
Esempio n. 14
0
 /**
  * If a types resource has changed and the new type is mapped to another document type, then the old document is removed
  * @param $uri
  * @param $types
  * @param $oldType
  * @return bool
  */
 protected function deleteOldDocument($uri, $types, $oldType)
 {
     $newTypes = array();
     foreach ($types as $type) {
         $type = (string) $type;
         if ($type && !empty($type)) {
             $newTypes[] = RdfNamespace::shorten($type);
         }
     }
     // Get most accurtype of oldtype
     $mostAccurateTypes = $this->filiationBuilder->getMostAccurateType(array(RdfNamespace::expand($oldType)), $this->serializerHelper->getAllTypes());
     $mostAccurateType = null;
     // not specified in project ontology description
     if (count($mostAccurateTypes) == 1) {
         $mostAccurateType = $mostAccurateTypes[0];
     } else {
         //            echo "Seems to not have to be indexed";
     }
     if (!in_array($mostAccurateType, $newTypes)) {
         $typesConfig = $this->configManager->getTypesConfigurationByClass($mostAccurateType);
         foreach ($typesConfig as $typeConfig) {
             $indexConfig = $typeConfig->getIndex();
             $index = $indexConfig->getName();
             $this->container->get('nemrod.elastica.jsonld.frame.loader')->setEsIndex($index);
             if ($index !== null) {
                 $esType = $this->indexRegistry->getIndex($index)->getType($typeConfig->getType());
                 // Trow an exeption if document does not exist
                 try {
                     $esType->deleteDocument(new Document($uri, array(), $mostAccurateType, $indexConfig->getElasticSearchName()));
                     return true;
                 } catch (\Exception $e) {
                 }
             }
         }
     }
     return false;
 }
Esempio n. 15
0
 protected function expandCurie($node, &$context, $value)
 {
     if (preg_match('/^(\\w*?):(.*)$/', $value, $matches)) {
         list(, $prefix, $local) = $matches;
         $prefix = strtolower($prefix);
         if ($prefix === '_') {
             // It is a bnode
             return $this->remapBnode(substr($value, 2));
         } elseif (empty($prefix) and $context['vocab']) {
             // Empty prefix
             return $context['vocab'] . $local;
         } elseif (isset($context['prefixes'][$prefix])) {
             return $context['prefixes'][$prefix] . $local;
         } elseif ($uri = $node->lookupNamespaceURI($prefix)) {
             return $uri . $local;
         } elseif (!empty($prefix) and $uri = RdfNamespace::get($prefix)) {
             // Expand using well-known prefixes
             return $uri . $local;
         }
     }
 }
Esempio n. 16
0
 /**
  * @param $shortUri
  *
  * @return string
  */
 public function expand($shortUri)
 {
     return RdfNamespace::expand($shortUri);
 }
Esempio n. 17
0
 /**
  * Method to serialise an EasyRdf\Graph to RDF/XML
  *
  * @param Graph  $graph  An EasyRdf\Graph object.
  * @param string $format The name of the format to convert to.
  * @param array  $options
  *
  * @return string The RDF in the new desired format.
  * @throws Exception
  */
 public function serialise(Graph $graph, $format, array $options = array())
 {
     parent::checkSerialiseParams($format);
     if ($format != 'rdfxml') {
         throw new Exception("EasyRdf\\Serialiser\\RdfXml does not support: {$format}");
     }
     // store of namespaces to be appended to the rdf:RDF tag
     $this->prefixes = array('rdf' => true);
     // store of the resource URIs we have serialised
     $this->outputtedResources = array();
     $xml = '';
     // Serialise URIs first
     foreach ($graph->resources() as $resource) {
         if (!$resource->isBnode()) {
             $xml .= $this->rdfxmlResource($resource, true);
         }
     }
     // Serialise bnodes afterwards
     foreach ($graph->resources() as $resource) {
         if ($resource->isBnode()) {
             $xml .= $this->rdfxmlResource($resource, true);
         }
     }
     // iterate through namepsaces array prefix and output a string.
     $namespaceStr = '';
     foreach ($this->prefixes as $prefix => $count) {
         $url = RdfNamespace::get($prefix);
         if (strlen($namespaceStr)) {
             $namespaceStr .= "\n        ";
         }
         if (strlen($prefix) === 0) {
             $namespaceStr .= ' xmlns="' . htmlspecialchars($url) . '"';
         } else {
             $namespaceStr .= ' xmlns:' . $prefix . '="' . htmlspecialchars($url) . '"';
         }
     }
     return "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n" . "<rdf:RDF" . $namespaceStr . ">\n" . $xml . "\n</rdf:RDF>\n";
 }
Esempio n. 18
0
 /**
  * Internal function to serialise an EasyRdf\Graph into a DOT formatted string
  *
  * @ignore
  */
 protected function serialiseDot(Graph $graph)
 {
     $result = "digraph {\n";
     // Write the graph attributes
     foreach ($this->attributes as $k => $v) {
         $result .= '  ' . $this->escape($k) . '=' . $this->escape($v) . ";\n";
     }
     // Go through each of the properties and write the edges
     $nodes = array();
     $result .= "\n  // Edges\n";
     foreach ($graph->resources() as $resource) {
         $name1 = $this->nodeName($resource);
         foreach ($resource->propertyUris() as $property) {
             $label = null;
             if ($this->useLabels) {
                 $label = $graph->resource($property)->label();
             }
             if ($label === null) {
                 if ($this->onlyLabelled == true) {
                     continue;
                 } else {
                     $label = RdfNamespace::shorten($property);
                 }
             }
             foreach ($resource->all("<{$property}>") as $value) {
                 $name2 = $this->nodeName($value);
                 $nodes[$name1] = $resource;
                 $nodes[$name2] = $value;
                 $result .= $this->serialiseRow($name1, $name2, array('label' => $label));
             }
         }
     }
     ksort($nodes);
     $result .= "\n  // Nodes\n";
     foreach ($nodes as $name => $node) {
         $type = substr($name, 0, 1);
         $label = '';
         if ($type == 'R') {
             if ($this->useLabels) {
                 $label = $node->label();
             }
             if (!$label) {
                 $label = $node->shorten();
             }
             if (!$label) {
                 $label = $node->getURI();
             }
             $result .= $this->serialiseRow($name, null, array('URL' => $node->getURI(), 'label' => $label, 'shape' => 'ellipse', 'color' => 'blue'));
         } elseif ($type == 'B') {
             if ($this->useLabels) {
                 $label = $node->label();
             }
             $result .= $this->serialiseRow($name, null, array('label' => $label, 'shape' => 'circle', 'color' => 'green'));
         } else {
             $result .= $this->serialiseRow($name, null, array('label' => strval($node), 'shape' => 'record'));
         }
     }
     $result .= "}\n";
     return $result;
 }