Skip to content

Commit

Permalink
Merge pull request #108 from jmccrae/shacl
Browse files Browse the repository at this point in the history
Implement SHACL validation
  • Loading branch information
michmech authored Mar 28, 2024
2 parents 2e88291 + 891482b commit 8e51528
Show file tree
Hide file tree
Showing 16 changed files with 846 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<itemizedlist>
<title>Properties</title>
<listitem>
<para><literal>dmlex:langCode</literal> REQUIRED (exactly 1) of type <literal>http://www.w3.org/2001/XMLSchema#language</literal></para>
<para><literal>dmlex:langCode</literal> REQUIRED (exactly 1) of type <literal>http://www.w3.org/2001/XMLSchema#language</literal> (subproperty of <literal>http://www.w3.org/ns/lemon/lime#language</literal>)</para>
</listitem>
<listitem>
<para><literal>dmlex:displayName</literal> OPTIONAL (at most 1) of type <literal>http://www.w3.org/2001/XMLSchema#string</literal></para>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<para><literal>dmlex:listingOrder</literal> REQUIRED (exactly 1) of type <literal>http://www.w3.org/2001/XMLSchema#nonNegativeInteger</literal></para>
</listitem>
<listitem>
<para><literal>dmlex:language</literal> REQUIRED (exactly 1) of type <literal>http://www.w3.org/2001/XMLSchema#language</literal> (subproperty of <literal>http://www.w3.org/ns/lemon/lime#language</literal>)</para>
<para><literal>dmlex:langCode</literal> OPTIONAL of type <literal>http://www.w3.org/2001/XMLSchema#language</literal> (subproperty of <literal>http://www.w3.org/ns/lemon/lime#language</literal>)</para>
</listitem>
<listitem>
<para><literal>dmlex:partOfSpeech</literal> OPTIONAL reference to <olink targetptr="rdf_PartOfSpeech">PartOfSpeech</olink></para>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<para><literal>dmlex:listingOrder</literal> OPTIONAL of type <literal>http://www.w3.org/2001/XMLSchema#nonNegativeInteger</literal></para>
</listitem>
<listitem>
<para><literal>dmlex:language</literal> OPTIONAL (at most 1) of type <literal>http://www.w3.org/2001/XMLSchema#language</literal> (subproperty of <literal>http://www.w3.org/ns/lemon/lime#language</literal>)</para>
<para><literal>dmlex:langCode</literal> OPTIONAL of type <literal>http://www.w3.org/2001/XMLSchema#language</literal> (subproperty of <literal>http://www.w3.org/ns/lemon/lime#language</literal>)</para>
</listitem>
<listitem>
<para><literal>dmlex:label</literal> OPTIONAL reference to <olink targetptr="rdf_Label">Label</olink></para>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<itemizedlist>
<title>Properties</title>
<listitem>
<para><literal>dmlex:language</literal> OPTIONAL (at most 1) of type <literal>http://www.w3.org/2001/XMLSchema#language</literal> (subproperty of <literal>http://www.w3.org/ns/lemon/lime#language</literal>)</para>
<para><literal>dmlex:langCode</literal> OPTIONAL of type <literal>http://www.w3.org/2001/XMLSchema#language</literal> (subproperty of <literal>http://www.w3.org/ns/lemon/lime#language</literal>)</para>
</listitem>
<listitem>
<para><literal>dmlex:text</literal> REQUIRED (exactly 1) of type <literal>http://www.w3.org/2000/01/rdf-schema#Literal</literal></para>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<para><literal>dmlex:listingOrder</literal> REQUIRED (exactly 1) of type <literal>http://www.w3.org/2001/XMLSchema#nonNegativeInteger</literal></para>
</listitem>
<listitem>
<para><literal>dmlex:language</literal> OPTIONAL (at most 1) of type <literal>http://www.w3.org/2001/XMLSchema#language</literal> (subproperty of <literal>http://www.w3.org/ns/lemon/lime#language</literal>)</para>
<para><literal>dmlex:langCode</literal> OPTIONAL of type <literal>http://www.w3.org/2001/XMLSchema#language</literal> (subproperty of <literal>http://www.w3.org/ns/lemon/lime#language</literal>)</para>
</listitem>
<listitem>
<para><literal>dmlex:partOfSpeech</literal> OPTIONAL reference to <olink targetptr="rdf_PartOfSpeech">PartOfSpeech</olink></para>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
<para><literal>dmlex:etymonLanguage</literal> OPTIONAL reference to <olink targetptr="rdf_EtymonLanguage">EtymonLanguage</olink></para>
</listitem>
<listitem>
<para><literal>dmlex:language</literal> REQUIRED (exactly 1) of type <literal>http://www.w3.org/2001/XMLSchema#language</literal> (subproperty of <literal>http://www.w3.org/ns/lemon/lime#language</literal>)</para>
<para><literal>dmlex:langCode</literal> REQUIRED (exactly 1) of type <literal>http://www.w3.org/2001/XMLSchema#language</literal> (subproperty of <literal>http://www.w3.org/ns/lemon/lime#language</literal>)</para>
</listitem>
</itemizedlist>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@
<para><literal>dmlex:listingOrder</literal> REQUIRED (exactly 1) of type <literal>http://www.w3.org/2001/XMLSchema#nonNegativeInteger</literal></para>
</listitem>
<listitem>
<para><literal>dmlex:ref</literal> REQUIRED (exactly 1) of type
<literal>http://www.w3.org/2001/XMLSchema#string</literal></para>
<para><literal>dmlex:ref</literal> REQUIRED (exactly 1) of type <literal>http://www.w3.org/2001/XMLSchema#string</literal></para>
</listitem>
<listitem>
<para><literal>dmlex:obverseListingOrder</literal> OPTIONAL (at most 1) of type
<literal>http://www.w3.org/2001/XMLSchema#integer</literal></para>
<para><literal>dmlex:obverseListingOrder</literal> OPTIONAL (at most 1) of type <literal>http://www.w3.org/2001/XMLSchema#integer</literal></para>
</listitem>
<listitem>
<para><literal>dmlex:role</literal> OPTIONAL (at most 1) of type <literal>http://www.w3.org/2001/XMLSchema#string</literal></para>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<para><literal>dmlex:description</literal> OPTIONAL (at most 1) of type <literal>http://www.w3.org/2000/01/rdf-schema#Literal</literal></para>
</listitem>
<listitem>
<para><literal>dmlex:type</literal> OPTIONAL of type <literal>http://www.w3.org/2001/XMLSchema#string</literal></para>
<para><literal>dmlex:type</literal> REQUIRED (exactly 1) of type <literal>http://www.w3.org/2001/XMLSchema#string</literal></para>
</listitem>
<listitem>
<para><literal>dmlex:role</literal> OPTIONAL (at most 1) of type <literal>http://www.w3.org/2001/XMLSchema#string</literal></para>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<para><literal>dmlex:label</literal> OPTIONAL reference to <olink targetptr="rdf_Label">Label</olink></para>
</listitem>
<listitem>
<para><literal>dmlex:indicator</literal> OPTIONAL (at most 1) reference to <olink targetptr="rdf_Indicator">Indicator</olink></para>
<para><literal>dmlex:indicator</literal> OPTIONAL (at most 1) of type <literal>http://www.w3.org/2000/01/rdf-schema#Literal</literal></para>
</listitem>
<listitem>
<para><literal>dmlex:definition</literal> OPTIONAL reference to <olink targetptr="rdf_Definition">Definition</olink></para>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<para><literal>dmlex:listingOrder</literal> REQUIRED (exactly 1) of type <literal>http://www.w3.org/2001/XMLSchema#nonNegativeInteger</literal></para>
</listitem>
<listitem>
<para><literal>dmlex:langCode</literal> REQUIRED (exactly 1) of type <literal>http://www.w3.org/2001/XMLSchema#language</literal></para>
<para><literal>dmlex:langCode</literal> REQUIRED (exactly 1) of type <literal>http://www.w3.org/2001/XMLSchema#language</literal> (subproperty of <literal>http://www.w3.org/ns/lemon/lime#language</literal>)</para>
</listitem>
</itemizedlist>

Expand Down
87 changes: 87 additions & 0 deletions dmlex-v1.0/specification/serializations/RDF/gen_shacl_from_rdf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import rdflib
from collections import defaultdict
from rdflib.namespace import RDF, RDFS, OWL, URIRef
from rdflib.collection import Collection

DMLEX = "http://www.oasis-open.org/to-be-confirmed/dmlex#"
DMLEX_SHACL = "http://www.oasis-open.org/to-be-confirmed/dmlex-shacl#"

def parse_rdf():
g = rdflib.Graph()
g.parse("ontology/dmlex.ttl", format="turtle")

props = defaultdict(list)
for s, p, o in g.triples((None, RDFS.domain, None)):
if isinstance(o, rdflib.term.URIRef):
if str(o).startswith(DMLEX + "Has"):
for domain_class in g.subjects(RDFS.subClassOf, o):
props[domain_class].append(s)
else:
props[o].append(s)
else:
for listname in g.objects(o, OWL.unionOf):
for item in Collection(g, listname):
props[item].append(s)

ranges = defaultdict(list)
for s, p, o in g.triples((None, RDFS.range, None)):
if isinstance(o, rdflib.term.URIRef):
ranges[s].append(o)

with open("ontology/dmlex.shacl", "w") as file:
file.write("# This file was generated from dmlex.ttl by " +
"gen_shacl_from_rdf.py\n")
file.write("@prefix sh: <http://www.w3.org/ns/shacl#> .\n")
file.write(f"@prefix dmlex: <{DMLEX}> .\n")
file.write(f"@prefix : <{DMLEX_SHACL}> .\n\n")
for class_uri in g.subjects(RDF.type, OWL.Class):
if (isinstance(class_uri, rdflib.term.URIRef) and
not str(class_uri).startswith(DMLEX + "Has")):
uri = str(class_uri)
name = uri.split("#")[-1]

subclasses = []
restrictions = defaultdict(lambda: defaultdict(lambda: [0,-1]))
for o in g.objects(class_uri, RDFS.subClassOf):
if (isinstance(o, rdflib.term.URIRef) and
not str(o).startswith(DMLEX + "Has")):
subclasses.append(str(o))
elif isinstance(o, rdflib.term.BNode):
for o2 in g.objects(o, OWL.onProperty):
for o3 in g.objects(o, OWL.cardinality):
restrictions[class_uri][o2] = [o3, o3]
for o3 in g.objects(o, OWL.maxCardinality):
restrictions[class_uri][o2] = [0, o3]
for o3 in g.objects(o, OWL.minCardinality):
restrictions[class_uri][o2] = [o3, -1]
file.write(f"""
:{name}Shape ;
a sh:NodeShape ;
sh:targetClass dmlex:{name} ;
sh:closed false""")
for prop in props[class_uri]:
file.write(f""" ;
sh:property [
sh:path dmlex:{prop.split("#")[-1]} """)
if prop in restrictions[class_uri]:
min_card, max_card = restrictions[class_uri][prop]
if min_card >= 0:
file.write(f""" ;
sh:minCount {min_card}""")
if max_card >= 0:
file.write(f""" ;
sh:maxCount {max_card}""")
for range in ranges[prop]:
if range.startswith(DMLEX):
file.write(f""" ;
sh:class dmlex:{range.split("#")[-1]} """)
file.write(" ]")

file.write(" .\n\n")





if __name__ == "__main__":
parse_rdf()
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ dmlex:LexicographicResource a owl:Class ;
rdfs:label "Lexicographic resource"@en ;
rdfs:subClassOf [
a owl:Restriction ;
owl:onProperty dmlex:language ;
owl:onProperty dmlex:langCode ;
owl:cardinality 1 ] , [
a owl:Restriction ;
owl:onProperty dmlex:title ;
Expand All @@ -59,17 +59,17 @@ dmlex:uri a owl:DatatypeProperty ;
rdfs:domain dmlex:LexicographicResource ;
rdfs:range xsd:anyURI .

dmlex:language a owl:DatatypeProperty ;
dmlex:langCode a owl:DatatypeProperty ;
rdfs:label "Language"@en ;
rdfs:domain dmlex:HasLanguage ;
rdfs:domain dmlex:HasLangCode ;
rdfs:range xsd:language ;
rdfs:subPropertyOf lime:language .

dmlex:LexicographicResource rdfs:subClassOf dmlex:HasLanguage .
dmlex:HeadwordTranslation rdfs:subClassOf dmlex:HasLanguage .
dmlex:HeadwordExplanation rdfs:subClassOf dmlex:HasLanguage .
dmlex:ExampleTranslation rdfs:subClassOf dmlex:HasLanguage .
dmlex:EtymonUnit rdfs:subClassOf dmlex:HasLanguage .
dmlex:LexicographicResource rdfs:subClassOf dmlex:HasLangCode .
dmlex:HeadwordTranslation rdfs:subClassOf dmlex:HasLangCode .
dmlex:HeadwordExplanation rdfs:subClassOf dmlex:HasLangCode .
dmlex:ExampleTranslation rdfs:subClassOf dmlex:HasLangCode .
dmlex:EtymonUnit rdfs:subClassOf dmlex:HasLangCode .

dmlex:entry a owl:ObjectProperty ;
rdfs:label "Entry"@en ;
Expand Down Expand Up @@ -217,7 +217,7 @@ dmlex:Sense a owl:Class ;
dmlex:indicator a owl:ObjectProperty ;
rdfs:label "Indicator"@en ;
rdfs:domain dmlex:Sense ;
rdfs:range dmlex:Indicator .
rdfs:range rdfs:Literal .

dmlex:definition a owl:ObjectProperty ;
rdfs:label "Definition"@en ;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ dmlex:Member a owl:Class ;
rdfs:label "Member"@en ;
rdfs:subClassOf [
a owl:Restriction ;
owl:onProperty dmlex:memberID ;
owl:onProperty dmlex:ref ;
owl:cardinality 1 ] , [
a owl:Restriction ;
owl:onProperty dmlex:role ;
Expand All @@ -67,10 +67,10 @@ dmlex:Member a owl:Class ;
owl:cardinality 1 ] , [
a owl:Restriction ;
owl:onProperty dmlex:obverseListingOrder ;
owl:cardinality 1 ] .
owl:maxCardinality 1 ] .

dmlex:memberID a owl:DatatypeProperty ;
rdfs:label "Member ID"@en ;
dmlex:ref a owl:DatatypeProperty ;
rdfs:label "Ref"@en ;
rdfs:domain dmlex:Member ;
rdfs:range xsd:string .

Expand Down
Loading

0 comments on commit 8e51528

Please sign in to comment.