From 88beb7f6810003e7f1e286c97d300f30f480ba2f Mon Sep 17 00:00:00 2001 From: Thomas Francart Date: Mon, 4 Dec 2017 11:59:17 +0100 Subject: [PATCH 1/5] Added SPARQL query to query for super properties of a property --- model/sparql/GenericSparql.php | 42 +++++++++++++++++++++++++ tests/GenericSparqlTest.php | 12 +++++++ tests/test-vocab-data/myns-ontology.ttl | 21 +++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 tests/test-vocab-data/myns-ontology.ttl diff --git a/model/sparql/GenericSparql.php b/model/sparql/GenericSparql.php index 544229b6e..181daf3c9 100644 --- a/model/sparql/GenericSparql.php +++ b/model/sparql/GenericSparql.php @@ -1358,6 +1358,48 @@ public function queryLabel($uri, $lang) { return null; } } + + /** + * Generates a SPARQL query to retrieve the super properties of a given property URI. + * Note this must be executed in the graph where this information is available. + * @param string $uri + * @return string sparql query string + */ + private function generateSubPropertyOfQuery($uri) { + $fcl = $this->generateFromClause(); + $query = << rdfs:subPropertyOf ?superProperty +} +EOQ; + return $query; + } + + /** + * Query the super properties of a provided property URI. + * @param string $uri URI of a propertyes + * @return array array super properties, or null if none exist + */ + public function querySuperProperties($uri) { + $query = $this->generateSubPropertyOfQuery($uri); + $result = $this->query($query); + $ret = array(); + foreach ($result as $row) { + if (isset($row->superProperty)) { + $ret[] = $row->superProperty->getUri(); + } + + } + + if (sizeof($ret) > 0) { + // return result + return $ret; + } else { + // no result, return null + return null; + } + } /** diff --git a/tests/GenericSparqlTest.php b/tests/GenericSparqlTest.php index 7afc2065e..15fb16b7a 100644 --- a/tests/GenericSparqlTest.php +++ b/tests/GenericSparqlTest.php @@ -922,4 +922,16 @@ public function testQueryConceptsWithExtraFields() $this->assertEquals(array('en' => 'Bass'), $actual[0]['prefLabels']); $this->assertEquals(array(0 => array('uri' => 'http://www.skosmos.skos/test/ta1')), $actual[0]['skos:broader']); } + + /** + * @covers GenericSparql::querySuperProperties + */ + public function testQuerySuperProperties() + { + $this->sparql = new GenericSparql('http://localhost:3030/ds/sparql', '?graph', $this->model); + $actual = $this->sparql->querySuperProperties('http://example.com/myns#property'); + $this->assertEquals(1, sizeof($actual)); + $expected = array('http://example.com/myns#superProperty'); + $this->assertEquals($actual, $expected); + } } diff --git a/tests/test-vocab-data/myns-ontology.ttl b/tests/test-vocab-data/myns-ontology.ttl new file mode 100644 index 000000000..e82ccc9d1 --- /dev/null +++ b/tests/test-vocab-data/myns-ontology.ttl @@ -0,0 +1,21 @@ +@prefix prefix: . +@prefix skos: . +@prefix owl: . +@prefix rdfs: . +@prefix my: . +@prefix xsd: . + + a owl:Ontology . + +my:superProperty a owl:DatatypeProperty ; + rdfs:domain skos:Concept ; + rdfs:label "my super property"@en ; + rdfs:range xsd:string . + +my:property a owl:DatatypeProperty ; + rdfs:domain skos:Concept ; + rdfs:label "my property"@en ; + rdfs:subPropertyOf my:superProperty ; + rdfs:range xsd:string . + + From 0fc6f907ebfd199d978c44aa0ffffcbadf127e2b Mon Sep 17 00:00:00 2001 From: Thomas Francart Date: Mon, 4 Dec 2017 13:13:54 +0100 Subject: [PATCH 2/5] Used graph-agnostic queries through default endpoint to retrieve label and superproperty of a property. --- model/Concept.php | 27 +++++++++++++++++++-------- tests/test-vocab-data/dup.ttl | 11 +++++++---- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/model/Concept.php b/model/Concept.php index 05bd7c791..2ddbfbca6 100644 --- a/model/Concept.php +++ b/model/Concept.php @@ -319,8 +319,10 @@ public function getProperties() $properties['skos:narrower'] = $membersArray; } } - + foreach ($longUris as &$prop) { + // storing full URI without brackets in a separate variable + $longUri = $prop; if (EasyRdf\RdfNamespace::shorten($prop) !== null) { // shortening property labels if possible $prop = $sprop = EasyRdf\RdfNamespace::shorten($prop); @@ -330,11 +332,17 @@ public function getProperties() // EasyRdf requires full URIs to be in angle brackets if (!in_array($prop, $this->DELETED_PROPERTIES) || ($this->isGroup() === false && $prop === 'skos:member')) { - $propres = new EasyRdf\Resource($prop, $this->graph); - $proplabel = $propres->label($this->getEnvLang()) ? $propres->label($this->getEnvLang()) : $propres->label(); - $superprop = $propres->get('rdfs:subPropertyOf') ? $propres->get('rdfs:subPropertyOf')->getURI() : null; + // retrieve property label and super properties from default SPARQL endoint + // note that this imply that the property has an rdf:type declared for the query to work + $envLangLabels = $this->model->getDefaultSparql()->queryLabel($longUri, $this->getEnvLang()); + $proplabel = ($envLangLabels)?$envLangLabels[$this->getEnvLang()]:$this->model->getDefaultSparql()->queryLabel($longUri, '')['']; + + // we're reading only one super property, even if there are multiple ones + $superprops = $this->model->getDefaultSparql()->querySuperProperties($longUri); + $superprop = ($superprops)?$superprops[0]:null; if ($superprop) { - $superprop = EasyRdf\RdfNamespace::shorten($superprop) ? EasyRdf\RdfNamespace::shorten($superprop) : $superprop; + $withBrackets = "<".$superprop.">"; + $superprop = EasyRdf\RdfNamespace::shorten($withBrackets) ? EasyRdf\RdfNamespace::shorten($withBrackets) : $superprop; } $propobj = new ConceptProperty($prop, $proplabel, $superprop); @@ -344,9 +352,12 @@ public function getProperties() } // searching for subproperties of literals too - foreach ($this->graph->allResources($prop, 'rdfs:subPropertyOf') as $subi) { - $suburi = EasyRdf\RdfNamespace::shorten($subi->getUri()) ? EasyRdf\RdfNamespace::shorten($subi->getUri()) : $subi->getUri(); - $duplicates[$suburi] = $prop; + if($superprops) { + foreach ($superprops as $subi) { + $withBrackets = "<".$subi.">"; + $suburi = EasyRdf\RdfNamespace::shorten($withBrackets) ? EasyRdf\RdfNamespace::shorten($withBrackets) : $subi; + $duplicates[$suburi] = $prop; + } } // Iterating through every literal and adding these to the data object. diff --git a/tests/test-vocab-data/dup.ttl b/tests/test-vocab-data/dup.ttl index 821509b8a..1f31e070a 100644 --- a/tests/test-vocab-data/dup.ttl +++ b/tests/test-vocab-data/dup.ttl @@ -31,15 +31,18 @@ dup:d5 a skos:Concept ; dup:prop4 "Identical property value"@en; skos:prefLabel "Not a subproperty"@en . -dup:prop1 +# in order for getLabel query to work, a type has to be declared +# on the properties + +dup:prop1 a owl:DatatypeProperty ; rdfs:label "Very nice property"@en . -dup:prop2 +dup:prop2 a owl:DatatypeProperty ; rdfs:subPropertyOf dup:prop1 ; rdfs:label "Nearly as nice subproperty"@en . -dup:prop3 +dup:prop3 a owl:DatatypeProperty ; rdfs:label "Nice-ish property"@en . -dup:prop4 +dup:prop4 a owl:DatatypeProperty ; rdfs:label "Not at all a subproperty"@en . From 0448f42b14b4b147c765fd0943d12e408a822135 Mon Sep 17 00:00:00 2001 From: Thomas Francart Date: Mon, 4 Dec 2017 14:40:54 +0100 Subject: [PATCH 3/5] Fixed call to Namespace.shorten(). Added types to property declarations in test files. --- model/Concept.php | 6 ++---- tests/test-vocab-data/date.ttl | 3 ++- tests/test-vocab-data/sub.ttl | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/model/Concept.php b/model/Concept.php index 2ddbfbca6..c60281dd0 100644 --- a/model/Concept.php +++ b/model/Concept.php @@ -341,8 +341,7 @@ public function getProperties() $superprops = $this->model->getDefaultSparql()->querySuperProperties($longUri); $superprop = ($superprops)?$superprops[0]:null; if ($superprop) { - $withBrackets = "<".$superprop.">"; - $superprop = EasyRdf\RdfNamespace::shorten($withBrackets) ? EasyRdf\RdfNamespace::shorten($withBrackets) : $superprop; + $superprop = EasyRdf\RdfNamespace::shorten($superprop) ? EasyRdf\RdfNamespace::shorten($superprop) : $superprop; } $propobj = new ConceptProperty($prop, $proplabel, $superprop); @@ -354,8 +353,7 @@ public function getProperties() // searching for subproperties of literals too if($superprops) { foreach ($superprops as $subi) { - $withBrackets = "<".$subi.">"; - $suburi = EasyRdf\RdfNamespace::shorten($withBrackets) ? EasyRdf\RdfNamespace::shorten($withBrackets) : $subi; + $suburi = EasyRdf\RdfNamespace::shorten($subi) ? EasyRdf\RdfNamespace::shorten($subi) : $subi; $duplicates[$suburi] = $prop; } } diff --git a/tests/test-vocab-data/date.ttl b/tests/test-vocab-data/date.ttl index c04c37f70..06fb8967f 100644 --- a/tests/test-vocab-data/date.ttl +++ b/tests/test-vocab-data/date.ttl @@ -8,6 +8,7 @@ @prefix skosmos: . @prefix xml: . @prefix xsd: . +@prefix owl: . date:d1 a skos:Concept, meta:TestClass ; dc:created "2000-01-03T12:46:39+03:00"^^xsd:dateTime ; @@ -19,7 +20,7 @@ date:d2 a skos:Concept, meta:TestClass ; date:ownDate "1986-21-00"^^xsd:date ; #invalid on purpose skos:prefLabel "Broken date"@en . -date:ownDate +date:ownDate a owl:DatatypeProperty ; rdfs:label "This is also a dateTime" . a owl:Ontology ; diff --git a/tests/test-vocab-data/sub.ttl b/tests/test-vocab-data/sub.ttl index 27deedd03..24edb17cd 100644 --- a/tests/test-vocab-data/sub.ttl +++ b/tests/test-vocab-data/sub.ttl @@ -14,6 +14,6 @@ sub:d1 a skos:Concept ; skos:prefLabel "Has a hidden property"@en ; sub:prop1 "Do not show this"@en . -sub:prop1 +sub:prop1 a owl:DatatypeProperty ; rdfs:subPropertyOf skos:hiddenLabel ; rdfs:label "This subproperty should not be shown in the UI"@en . From 8359d9b6e1c50414e7fa11015c28b4f69aa690f0 Mon Sep 17 00:00:00 2001 From: Thomas Francart Date: Tue, 19 Dec 2017 16:13:02 +0100 Subject: [PATCH 4/5] Read property label from current vocabulary before querying the default graph --- model/Concept.php | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/model/Concept.php b/model/Concept.php index c60281dd0..317b4487a 100644 --- a/model/Concept.php +++ b/model/Concept.php @@ -331,14 +331,27 @@ public function getProperties() } // EasyRdf requires full URIs to be in angle brackets - if (!in_array($prop, $this->DELETED_PROPERTIES) || ($this->isGroup() === false && $prop === 'skos:member')) { - // retrieve property label and super properties from default SPARQL endoint + if (!in_array($prop, $this->DELETED_PROPERTIES) || ($this->isGroup() === false && $prop === 'skos:member')) { + + // retrieve property label and super properties from the current vocabulary first // note that this imply that the property has an rdf:type declared for the query to work - $envLangLabels = $this->model->getDefaultSparql()->queryLabel($longUri, $this->getEnvLang()); - $proplabel = ($envLangLabels)?$envLangLabels[$this->getEnvLang()]:$this->model->getDefaultSparql()->queryLabel($longUri, '')['']; + $envLangLabels = $this->vocab->getSparql()->queryLabel($longUri, $this->getEnvLang()); + $proplabel = ($envLangLabels)?$envLangLabels[$this->getEnvLang()]:$this->vocab->getSparql()->queryLabel($longUri, '')['']; + + // if not found in current vocabulary, look up in the default graph to be able + // to read an ontology loaded in a separate graph + if(!$proplabel) { + $envLangLabels = $this->model->getDefaultSparql()->queryLabel($longUri, $this->getEnvLang()); + $proplabel = ($envLangLabels)?$envLangLabels[$this->getEnvLang()]:$this->model->getDefaultSparql()->queryLabel($longUri, '')['']; + } + + $superprops = $this->vocab->getSparql()->querySuperProperties($longUri); + // also look up superprops in the default graph if not found in current vocabulary + if(!$superprops) { + $superprops = $this->model->getDefaultSparql()->querySuperProperties($longUri); + } // we're reading only one super property, even if there are multiple ones - $superprops = $this->model->getDefaultSparql()->querySuperProperties($longUri); $superprop = ($superprops)?$superprops[0]:null; if ($superprop) { $superprop = EasyRdf\RdfNamespace::shorten($superprop) ? EasyRdf\RdfNamespace::shorten($superprop) : $superprop; From 41f54ffb0d0a62f63b03f17e813ded4e6b56b258 Mon Sep 17 00:00:00 2001 From: Thomas Francart Date: Wed, 3 Jan 2018 16:57:00 +0100 Subject: [PATCH 5/5] Look for property label and superproperties in the current EasyRdf Model rather than making another SPARQL query. --- model/Concept.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/model/Concept.php b/model/Concept.php index 317b4487a..df3a5739d 100644 --- a/model/Concept.php +++ b/model/Concept.php @@ -332,20 +332,24 @@ public function getProperties() // EasyRdf requires full URIs to be in angle brackets if (!in_array($prop, $this->DELETED_PROPERTIES) || ($this->isGroup() === false && $prop === 'skos:member')) { - - // retrieve property label and super properties from the current vocabulary first - // note that this imply that the property has an rdf:type declared for the query to work - $envLangLabels = $this->vocab->getSparql()->queryLabel($longUri, $this->getEnvLang()); - $proplabel = ($envLangLabels)?$envLangLabels[$this->getEnvLang()]:$this->vocab->getSparql()->queryLabel($longUri, '')['']; + // retrieve property label and super properties from the current vocabulary first + $propres = new EasyRdf\Resource($prop, $this->graph); + $proplabel = $propres->label($this->getEnvLang()) ? $propres->label($this->getEnvLang()) : $propres->label(); // if not found in current vocabulary, look up in the default graph to be able // to read an ontology loaded in a separate graph + // note that this imply that the property has an rdf:type declared for the query to work if(!$proplabel) { $envLangLabels = $this->model->getDefaultSparql()->queryLabel($longUri, $this->getEnvLang()); $proplabel = ($envLangLabels)?$envLangLabels[$this->getEnvLang()]:$this->model->getDefaultSparql()->queryLabel($longUri, '')['']; } - $superprops = $this->vocab->getSparql()->querySuperProperties($longUri); + // look for superproperties in the current graph + $superprops = null; + foreach ($this->graph->allResources($prop, 'rdfs:subPropertyOf') as $subi) { + $superprops[] = $subi->getUri(); + } + // also look up superprops in the default graph if not found in current vocabulary if(!$superprops) { $superprops = $this->model->getDefaultSparql()->querySuperProperties($longUri);