OWL 2 SHACL semi-closed ruleset
type: Ontology
comment: Turns an OWL Ontology into a set of SHACL Shapes. Additionnal Shapes with sh:targetSubjectOf verify the domains of the ontology properties, ensuring each property is asserted on an instance of the correct class. Properties from other ontologies can still be asserted anywhere as the NodeShapes are not closed
source: from-owl-to-shacl-in-an-automated-way
provenance: This is derived from original work by TopQuadrant at https://www.topquadrant.com/from-owl-to-shacl-in-an-automated-way/, with their authorization.
declare: PrefixDeclaration
  namespace: http://data.sparna.fr/ontologies/owl2sh-semi-closed#
  prefix: owl2sh-semi-closed
declare: PrefixDeclaration
  namespace: http://www.w3.org/2000/01/rdf-schema#
  prefix: rdfs
declare: PrefixDeclaration
  namespace: http://www.w3.org/2002/07/owl#
  prefix: owl
declare: PrefixDeclaration
  namespace: http://www.w3.org/ns/shacl#
  prefix: sh
declare: PrefixDeclaration
  namespace: http://www.w3.org/2001/XMLSchema#
  prefix: xsd
declare: PrefixDeclaration
  namespace: http://www.w3.org/1999/02/22-rdf-syntax-ns#
  prefix: rdf
declare: PrefixDeclaration
  namespace: http://datashapes.org/dash#
  prefix: dash

ClassShape
type: NodeShape
rule: Copy owl:intersectionOfs from owl:equivalentClass
rule: Flatten owl:intersectionOf
rule: owl:onProperty to sh:property
rule: rdfs:domain to sh:property
rule: owl:equivalentClass/owl:hasValue to sh:NodeShape with sh:hasValue
rule: owl:FunctionalProperty to sh:maxCount 1
rule: owl:maxCardinality to sh:maxCount
rule: owl:minCardinality to sh:minCount
rule: owl:hasValue to sh:hasValue
rule: owl:someValuesFrom to sh:minCount 1
rule: owl:allValuesFrom with IRI to sh:class or sh:datatype
rule: owl:unionOf IRIs to rdfs:subClassOf
rule: rdfs:range with IRI to sh:class or sh:datatype
rule: rdfs:range rdfs:Literal to sh:nodeKind sh:Literal
rule: sh:property shape clean up
target: SPARQLTarget
  prefixes: OWL 2 SHACL semi-closed ruleset
  select: SELECT ?this WHERE { { { { ?type rdfs:subClassOf* rdfs:Class . ?this a ?type . } UNION { ?this a owl:Class . } } FILTER isIRI(?this) . } }

Copy owl:intersectionOfs from owl:equivalentClass
type: SPARQLRule
comment: Copies any intersections within owl:equivalentClass into the host class itself so that subsequent rules convert them further.
construct: CONSTRUCT { $this owl:intersectionOf ?inter . } WHERE { $this owl:equivalentClass ?equi . FILTER isBlank(?equi) . ?equi owl:intersectionOf ?inter . }
order: -1
prefixes: OWL 2 SHACL semi-closed ruleset

Flatten owl:intersectionOf
type: SPARQLRule
comment: Copies the members of an owl:intersectionOf list as superclasses into the host class itself. Subsequent rules then apply.
construct: CONSTRUCT { $this rdfs:subClassOf ?superClass . } WHERE { $this owl:intersectionOf ?list . ?list rdf:rest*/rdf:first ?superClass . FILTER isBlank(?superClass) . }
order: 0
prefixes: OWL 2 SHACL semi-closed ruleset

owl:onProperty to sh:property
type: SPARQLRule
comment: Creates a NodeShape and a sh:property shape for each property that is mentioned in an owl:Restriction.
construct: CONSTRUCT { $this a sh:NodeShape . $this a rdfs:Class . $this sh:property ?propertyShape . ?propertyShape sh:path ?property . } WHERE { $this rdfs:subClassOf/owl:onProperty ?property . BIND (owl2sh-semi-closed:getPropertyShape(?property, $this) AS ?propertyShape) . }
order: 1
prefixes: OWL 2 SHACL semi-closed ruleset

owl:equivalentClass/owl:hasValue to sh:NodeShape with sh:hasValue
type: SPARQLRule
comment: Creates a sh:property shape for each property that is mentioned in an owl:Restriction.
construct: CONSTRUCT { $this a sh:NodeShape . $this a rdfs:Class . $this sh:property ?propertyShape . ?propertyShape sh:path ?propertyProbablySkosInScheme . ?propertyShape sh:hasValue ?somethingProbablyAConceptScheme . } WHERE { $this owl:equivalentClass ?restriction . FILTER(isBlank(?restriction)) . ?restriction owl:hasValue ?somethingProbablyAConceptScheme . ?restriction owl:onProperty ?propertyProbablySkosInScheme . BIND (owl2sh-semi-closed:getPropertyShape(?propertyProbablySkosInScheme, $this) AS ?propertyShape) . }
order: 1
prefixes: OWL 2 SHACL semi-closed ruleset

rdfs:domain to sh:property
type: SPARQLRule
comment: Creates a NodeShape and a sh:property shape for each property with matching rdfs:domain.
construct: CONSTRUCT { $this a sh:NodeShape . $this a rdfs:Class . $this sh:property ?propertyShape . ?propertyShape sh:path ?property . } WHERE { { ?property rdfs:domain $this . } UNION { ?property rdfs:domain/owl:unionOf ?unionOf . ?unionOf rdf:rest*/rdf:first $this . } BIND (owl2sh-semi-closed:getPropertyShape(?property, $this) AS ?propertyShape) . }
order: 2
prefixes: OWL 2 SHACL semi-closed ruleset

owl:FunctionalProperty to sh:maxCount 1
type: SPARQLRule
comment: For each relevant property that is owl:FunctionalProperty, create sh:maxCount of 1 (unless there is an OWL cardinality restriction).
construct: CONSTRUCT { ?propertyShape sh:maxCount 1 . } WHERE { $this sh:property ?propertyShape . ?propertyShape sh:path ?property . ?property a owl:FunctionalProperty . FILTER NOT EXISTS { $this rdfs:subClassOf* ?class . ?class rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . ?restriction owl:maxCardinality|owl:cardinality ?any . } }
order: 3
prefixes: OWL 2 SHACL semi-closed ruleset

rdfs:range with IRI to sh:class or sh:datatype
type: SPARQLRule
comment: For each relevant property that has an rdfs:range, creates an sh:node if the range yielded a NodeShape that has an sh:hasValue constraint, instead of an sh:class
construct: CONSTRUCT { ?propertyShape sh:node [ sh:property [ sh:path ?propertyProbablySkosInScheme ; sh:hasValue ?somethingProbablyAConceptScheme ; ] ] . } WHERE { { $this sh:property ?propertyShape . } ?propertyShape sh:path ?property . ?property rdfs:range ?range . ?range owl:equivalentClass ?restriction . FILTER(isBlank(?restriction)) . ?restriction owl:hasValue ?somethingProbablyAConceptScheme . ?restriction owl:onProperty ?propertyProbablySkosInScheme . }
order: 4
prefixes: OWL 2 SHACL semi-closed ruleset

rdfs:range with IRI to sh:class or sh:datatype
type: SPARQLRule
comment: For each relevant property that has an rdfs:range, create sh:class or sh:datatype constraint unless it already exists (from a restriction).
construct: CONSTRUCT { ?propertyShape ?parameter ?range . } WHERE { { $this sh:property ?propertyShape . FILTER NOT EXISTS { ?propertyShape sh:node|sh:class|sh:datatype ?any } . } ?propertyShape sh:path ?property . ?property rdfs:range ?range . FILTER isIRI(?range) . # exclude the case where range is rdfs:Literal, this will be handled with an sh:kind FILTER(?range != rdfs:Literal) . BIND ( IF( ?range IN (xsd:boolean, xsd:string, xsd:date, xsd:dateTime, xsd:integer,xsd:integer, xsd:float, xsd:double, xsd:duration, xsd:anyURI, rdf:langString), sh:datatype, sh:class ) AS ?parameter) . }
order: 5
prefixes: OWL 2 SHACL semi-closed ruleset

rdfs:range rdfs:Literal to sh:nodeKind sh:Literal
type: SPARQLRule
comment: For each relevant property that has an rdfs:range with value rdfs:Literal, create sh:nodeKind constraint.
construct: CONSTRUCT { ?propertyShape sh:nodeKind sh:Literal . } WHERE { ?propertyShape sh:path ?property . ?property a owl:DatatypeProperty . ?property rdfs:range rdfs:Literal . }
order: 5
prefixes: OWL 2 SHACL semi-closed ruleset

owl:maxCardinality to sh:maxCount
type: SPARQLRule
comment: For each owl:maxCardinality restriction, create a corresponding sh:maxCount constraint.
construct: CONSTRUCT { ?propertyShape sh:maxCount ?maxCount . # ?restriction owl2sh-semi-closed:mappedTo ?propertyShape . } WHERE { $this rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . FILTER isBlank(?restriction) . ?restriction owl:onProperty ?property . ?restriction owl:maxCardinality|owl:cardinality ?raw . BIND (xsd:integer(?raw) AS ?maxCount) . BIND (owl2sh-semi-closed:getPropertyShape(?property, $this) AS ?propertyShape) . }
order: 6
prefixes: OWL 2 SHACL semi-closed ruleset

owl:maxQualifiedCardinality with owl:onClass to sh:maxCount
type: SPARQLRule
comment: For each owl:maxQualifiedCardinality restriction on an IRI class, create a corresponding sh:maxCount constraint, if the owl:onClass is identical to the rdfs:range of the property.
construct: PREFIX sh: <http://www.w3.org/ns/shacl#> PREFIX owl: <http://www.w3.org/2002/07/owl#> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> PREFIX owl2sh-semi-closed: <http://data.sparna.fr/ontologies/owl2sh-semi-closed#> CONSTRUCT { ?propertyShape sh:maxCount ?maxCount . # ?restriction owl2sh-semi-closed:mappedTo ?propertyShape . } WHERE { { $this rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . FILTER isBlank(?restriction) . } ?restriction owl:maxQualifiedCardinality ?raw . ?restriction owl:onProperty ?property . ?restriction owl:onClass ?onClass . FILTER isIRI(?onClass) . FILTER EXISTS { ?property rdfs:range ?onClass } . BIND (xsd:integer(?raw) AS ?maxCount) . BIND (owl2sh-semi-closed:getPropertyShape(?property, $this) AS ?propertyShape) . }
order: 6
prefixes: OWL 2 SHACL semi-closed ruleset

owl:maxQualifiedCardinality with owl:onClass to sh:qualifiedMaxCount
type: SPARQLRule
comment: For each owl:maxQualifiedCardinality restriction on an IRI class, create a corresponding (new) sh:qualifiedMaxCount constraint, unless the owl:onClass is identical to the rdfs:range of the property.
construct: CONSTRUCT { $this sh:property ?propertyShape . ?propertyShape sh:path ?property . ?propertyShape sh:qualifiedMaxCount ?maxCount . ?propertyShape sh:qualifiedValueShape ?valueShape . ?valueShape sh:class ?onClass . # ?restriction owl2sh-semi-closed:mappedTo ?propertyShape . } WHERE { { $this rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . FILTER isBlank(?restriction) . } ?restriction owl:maxQualifiedCardinality ?raw . ?restriction owl:onProperty ?property . ?restriction owl:onClass ?onClass . FILTER isIRI(?onClass) . FILTER NOT EXISTS { ?property rdfs:range ?onClass } . BIND (xsd:integer(?raw) AS ?maxCount) . BIND (BNODE() AS ?propertyShape) . BIND (BNODE() AS ?valueShape) . }
order: 6
prefixes: OWL 2 SHACL semi-closed ruleset

owl:maxQualifiedCardinality with owl:onDataRange to sh:qualifiedMaxCount
type: SPARQLRule
comment: For each owl:maxQualifiedCardinality restriction on an IRI datatype, create a corresponding (new) sh:qualifiedMaxCount constraint.
construct: CONSTRUCT { $this sh:property ?propertyShape . ?propertyShape sh:path ?property . ?propertyShape sh:qualifiedMaxCount ?maxCount . ?propertyShape sh:qualifiedValueShape ?valueShape . ?valueShape sh:datatype ?onDataRange . # ?restriction owl2sh-semi-closed:mappedTo ?propertyShape . } WHERE { { $this rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . FILTER isBlank(?restriction) . } ?restriction owl:maxQualifiedCardinality ?raw . ?restriction owl:onProperty ?property . ?restriction owl:onDataRange ?onDataRange . FILTER isIRI(?onDataRange) . FILTER NOT EXISTS { ?property rdfs:range ?onDataRange } . BIND (xsd:integer(?raw) AS ?maxCount) . BIND (BNODE() AS ?propertyShape) . BIND (BNODE() AS ?valueShape) . }
order: 6
prefixes: OWL 2 SHACL semi-closed ruleset

owl:minCardinality to sh:minCount
type: SPARQLRule
comment: For each owl:minCardinality restriction, create a corresponding sh:minCount constraint.
construct: CONSTRUCT { ?propertyShape sh:minCount ?maxCount . # ?restriction owl2sh-semi-closed:mappedTo ?propertyShape . } WHERE { { $this rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . FILTER isBlank(?restriction) . } ?restriction owl:minCardinality|owl:cardinality ?raw . ?restriction owl:onProperty ?property . BIND (xsd:integer(?raw) AS ?maxCount) . BIND (owl2sh-semi-closed:getPropertyShape(?property, $this) AS ?propertyShape) . }
order: 6
prefixes: OWL 2 SHACL semi-closed ruleset

owl:minQualifiedCardinality with owl:onClass to sh:minCount
type: SPARQLRule
comment: For each owl:minQualifiedCardinality restriction on an IRI class, create a corresponding sh:minCount constraint, if the owl:onClass is identical to the rdfs:range of the property.
construct: CONSTRUCT { ?propertyShape sh:minCount ?minCount . # ?restriction owl2sh-semi-closed:mappedTo ?propertyShape . } WHERE { { $this rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . FILTER isBlank(?restriction) . } ?restriction owl:minQualifiedCardinality ?raw . ?restriction owl:onClass ?onClass . ?restriction owl:onProperty ?property . FILTER isIRI(?onClass) . FILTER EXISTS { ?property rdfs:range ?onClass } . BIND (xsd:integer(?raw) AS ?minCount) . BIND (owl2sh-semi-closed:getPropertyShape(?property, $this) AS ?propertyShape) . }
order: 6
prefixes: OWL 2 SHACL semi-closed ruleset

owl:minQualifiedCardinality with owl:onClass to sh:qualifiedMinCount
type: SPARQLRule
comment: For each owl:minQualifiedCardinality restriction on an IRI class, create a corresponding (new) sh:qualifiedMinCount constraint, unless the owl:onClass is identical to the rdfs:range of the property.
construct: CONSTRUCT { $this sh:property ?propertyShape . ?propertyShape sh:path ?property . ?propertyShape sh:qualifiedMinCount ?minCount . ?propertyShape sh:qualifiedValueShape ?valueShape . ?valueShape sh:class ?onClass . # ?restriction owl2sh-semi-closed:mappedTo ?propertyShape . } WHERE { { $this rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . FILTER isBlank(?restriction) . } ?restriction owl:minQualifiedCardinality ?raw . ?restriction owl:onClass ?onClass . ?restriction owl:onProperty ?property . FILTER isIRI(?onClass) . FILTER NOT EXISTS { ?property rdfs:range ?onClass } . BIND (xsd:integer(?raw) AS ?minCount) . BIND (BNODE() AS ?propertyShape) . BIND (BNODE() AS ?valueShape) . }
order: 6
prefixes: OWL 2 SHACL semi-closed ruleset

owl:minQualifiedCardinality with owl:onDataRange to sh:qualifiedMinCount
type: SPARQLRule
comment: For each owl:minQualifiedCardinality restriction on an IRI datatype, create a corresponding (new) sh:qualifiedMinCount constraint.
construct: CONSTRUCT { $this sh:property ?propertyShape . ?propertyShape sh:path ?property . ?propertyShape sh:qualifiedMinCount ?minCount . ?propertyShape sh:qualifiedValueShape ?valueShape . ?valueShape sh:datatype ?onDataRange . # ?restriction owl2sh-semi-closed:mappedTo ?propertyShape . } WHERE { { $this rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . FILTER isBlank(?restriction) . } ?restriction owl:minQualifiedCardinality ?raw . ?restriction owl:onDataRange ?onDataRange . ?restriction owl:onProperty ?property . FILTER isIRI(?onDataRange) . FILTER NOT EXISTS { ?property rdfs:range ?onDataRange } . BIND (xsd:integer(?raw) AS ?minCount) . BIND (BNODE() AS ?propertyShape) . BIND (BNODE() AS ?valueShape) . }
order: 6
prefixes: OWL 2 SHACL semi-closed ruleset

owl:qualifiedCardinality with owl:onClass to sh:max/minCount
type: SPARQLRule
comment: For each owl:qualifiedCardinality restriction on an IRI class, create corresponding sh:max/minCount constraints, if the owl:onClass is identical to the rdfs:range of the property.
construct: CONSTRUCT { ?propertyShape sh:maxCount ?count . ?propertyShape sh:minCount ?count . # ?restriction owl2sh-semi-closed:mappedTo ?propertyShape . } WHERE { { $this rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . FILTER isBlank(?restriction) . } ?restriction owl:qualifiedCardinality ?raw . ?restriction owl:onClass ?onClass . ?restriction owl:onProperty ?property . FILTER isIRI(?onClass) . FILTER EXISTS { ?property rdfs:range ?onClass } . BIND (xsd:integer(?raw) AS ?count) . BIND (owl2sh-semi-closed:getPropertyShape(?property, $this) AS ?propertyShape) . }
order: 6
prefixes: OWL 2 SHACL semi-closed ruleset

owl:qualifiedCardinality with owl:onClass to sh:qualifiedMax/MinCount
type: SPARQLRule
comment: For each owl:qualifiedCardinality restriction on an IRI class, create a corresponding (new) sh:qualifiedMax/MinCount constraint, unless the owl:onClass is identical to the rdfs:range of the property.
construct: CONSTRUCT { $this sh:property ?propertyShape . ?propertyShape sh:path ?property . ?propertyShape sh:qualifiedMaxCount ?count . ?propertyShape sh:qualifiedMinCount ?count . ?propertyShape sh:qualifiedValueShape ?valueShape . ?valueShape sh:class ?onClass . # ?restriction owl2sh-semi-closed:mappedTo ?propertyShape . } WHERE { { $this rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . FILTER isBlank(?restriction) . } ?restriction owl:qualifiedCardinality ?raw . ?restriction owl:onClass ?onClass . ?restriction owl:onProperty ?property . FILTER isIRI(?onClass) . FILTER NOT EXISTS { ?property rdfs:range ?onClass } . BIND (xsd:integer(?raw) AS ?count) . BIND (BNODE() AS ?propertyShape) . BIND (BNODE() AS ?valueShape) . }
order: 6
prefixes: OWL 2 SHACL semi-closed ruleset

owl:qualifiedCardinality with owl:onDataRange to sh:qualifiedMax/MinCount
type: SPARQLRule
comment: For each owl:qualifiedCardinality restriction on an IRI datatype, create a corresponding (new) sh:qualifiedMax/MinCount constraint.
construct: CONSTRUCT { $this sh:property ?propertyShape . ?propertyShape sh:path ?property . ?propertyShape sh:qualifiedMaxCount ?count . ?propertyShape sh:qualifiedMinCount ?count . ?propertyShape sh:qualifiedValueShape ?valueShape . ?valueShape sh:datatype ?onDataRange . # ?restriction owl2sh-semi-closed:mappedTo ?propertyShape . } WHERE { { $this rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . FILTER isBlank(?restriction) . } ?restriction owl:qualifiedCardinality ?raw . ?restriction owl:onDataRange ?onDataRange . ?restriction owl:onProperty ?property . FILTER isIRI(?onDataRange) . FILTER NOT EXISTS { ?property rdfs:range ?onDataRange } . BIND (xsd:integer(?raw) AS ?count) . BIND (BNODE() AS ?propertyShape) . BIND (BNODE() AS ?valueShape) . }
order: 6
prefixes: OWL 2 SHACL semi-closed ruleset

owl:hasValue to sh:hasValue
type: SPARQLRule
comment: For each owl:hasValue restriction, create a corresponding sh:hasValue constraint.
construct: CONSTRUCT { ?propertyShape sh:hasValue ?hasValue . } WHERE { { $this rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . FILTER isBlank(?restriction) . } ?restriction owl:onProperty ?property . ?restriction owl:hasValue ?hasValue . BIND (owl2sh-semi-closed:getPropertyShape(?property, $this) AS ?propertyShape) . }
order: 8
prefixes: OWL 2 SHACL semi-closed ruleset

owl:someValuesFrom to sh:minCount 1
type: SPARQLRule
comment: For each owl:someValuesFrom restriction, create a corresponding sh:minCount 1 constraint.
construct: CONSTRUCT { ?propertyShape sh:minCount 1 . # ?restriction owl2sh-semi-closed:mappedTo ?propertyShape . } WHERE { $this rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . ?restriction owl:someValuesFrom ?someValuesFrom . ?restriction owl:onProperty ?property . BIND (owl2sh-semi-closed:getPropertyShape(?property, $this) AS ?propertyShape) . }
order: 4
prefixes: OWL 2 SHACL semi-closed ruleset

owl:someValuesFrom with IRI to dash:hasValueWithClass
type: SPARQLRule
comment: For each owl:someValuesFrom restriction combined with an owl:allValuesFrom on an IRI, create a corresponding dash:hasValueWithClass constraint using a path expression. For example: ex:ConstitutionalOwner a owl:Class ; rdfs:subClassOf [ a owl:Restriction ; owl:onProperty ex:isPlayedBy ; owl:someValuesFrom [ a owl:Restriction ; owl:allValuesFrom ex:StockholdersEquity ; owl:onProperty ex:holdsEquityIn ; ] ; ] . becomes ex:ConstitutionalOwner a sh:NodeShape ; sh:property [ sh:path ( ex:isPlayedBy ex:holdsEquityIn ) ; dash:hasValueWithClass ex:StockholdersEquity ; ] .
construct: CONSTRUCT { $this sh:property ?propertyShape . ?propertyShape dash:hasValueWithClass ?allValuesFrom . ?propertyShape sh:path ?firstNode . ?firstNode rdf:first ?property . ?firstNode rdf:rest ?secondNode . ?secondNode rdf:first ?allValuesFromProperty . ?secondNode rdf:rest rdf:nil . # ?restriction owl2sh-semi-closed:mappedTo ?propertyShape . } WHERE { { { $this rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . FILTER isBlank(?restriction) . } ?restriction owl:someValuesFrom ?someValuesFrom . ?someValuesFrom owl:allValuesFrom ?allValuesFrom . FILTER isIRI(?allValuesFrom) . FILTER (!(?allValuesFrom IN (xsd:boolean, xsd:string, xsd:date, xsd:dateTime, xsd:integer,xsd:integer, xsd:float, xsd:double, xsd:duration, xsd:anyURI))) . FILTER isBlank(?someValuesFrom) . } ?restriction owl:onProperty ?property . ?someValuesFrom owl:onProperty ?allValuesFromProperty . BIND (BNODE() AS ?propertyShape) . BIND (BNODE() AS ?firstNode) . BIND (BNODE() AS ?secondNode) . }
order: 7
prefixes: OWL 2 SHACL semi-closed ruleset

owl:unionOf IRIs to rdfs:subClassOf
type: SPARQLRule
comment: For each owl:unionOf that only consists of named classes, move these classes into "normal" rdfs:subClassOf triples.
construct: CONSTRUCT { $this rdfs:subClassOf ?class . # ?union owl2sh-semi-closed:mappedTo $this . } WHERE { { $this rdfs:subClassOf ?union . ?union owl:unionOf ?unionOf . FILTER isBlank(?union) . } FILTER NOT EXISTS { ?unionOf rdf:rest*/rdf:first ?member . FILTER (!isIRI(?member)) . } . ?unionOf rdf:rest*/rdf:first ?class . }
order: 4
prefixes: OWL 2 SHACL semi-closed ruleset

owl:someValuesFrom with IRI to dash:hasValueWithClass
type: SPARQLRule
comment: For each owl:someValuesFrom restriction with an IRI, create a corresponding dash:hasValueWithClass constraint.
construct: CONSTRUCT { ?propertyShape dash:hasValueWithClass ?someValuesFrom . # ?restriction owl2sh-semi-closed:mappedTo ?propertyShape . } WHERE { { $this rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . FILTER isBlank(?restriction) . } ?restriction owl:someValuesFrom ?someValuesFrom . ?restriction owl:onProperty ?property . FILTER (isIRI(?someValuesFrom)) FILTER (!(?someValuesFrom IN (xsd:boolean, xsd:string, xsd:date, xsd:dateTime, xsd:integer,xsd:integer, xsd:float, xsd:double, xsd:duration, xsd:anyURI))) . FILTER NOT EXISTS { ?property rdfs:range ?someValuesFrom } . BIND (owl2sh-semi-closed:getPropertyShape(?property, $this) AS ?propertyShape) . }
order: 4
prefixes: OWL 2 SHACL semi-closed ruleset

owl:allValuesFrom with IRI to sh:class or sh:datatype
type: SPARQLRule
comment: For each owl:allValuesFrom restriction, create a corresponding sh:class or sh:datatype constraint.
construct: CONSTRUCT { ?propertyShape ?parameter ?allValuesFrom . # ?restriction owl2sh-semi-closed:mappedTo ?propertyShape . } WHERE { { $this rdfs:subClassOf ?restriction . ?restriction a owl:Restriction . FILTER isBlank(?restriction) . } ?restriction owl:onProperty ?property . ?restriction owl:allValuesFrom ?allValuesFrom . FILTER isIRI(?allValuesFrom) . BIND (owl2sh-semi-closed:getPropertyShape(?property, $this) AS ?propertyShape) . BIND ( IF( (?allValuesFrom IN (xsd:boolean, xsd:string, xsd:date, xsd:dateTime, xsd:integer,xsd:integer, xsd:float, xsd:double, xsd:duration, xsd:anyURI)), sh:datatype, sh:class ) AS ?parameter ) . }
order: 4
prefixes: OWL 2 SHACL semi-closed ruleset

rdfs:domain with IRI to sh:NodeShape with sh:class
type: SPARQLRule
comment: For each rdfs:domain that is an IRI, create a NodeShape with a sh:targetSubjectsOf to this domain and a sh:class constraint.
construct: CONSTRUCT { ?propertyShape a sh:NodeShape . ?propertyShape sh:targetSubjectsOf ?property . ?propertyShape sh:class ?domain . } WHERE { ?property rdfs:domain ?domain . FILTER (isIRI(?domain)) . BIND(IRI(CONCAT(STR(?property), '-', 'shape')) AS ?propertyShape) }
order: 5
prefixes: OWL 2 SHACL semi-closed ruleset

sh:property shape clean up
type: SPARQLRule
comment: For each value of sh:property, add a rdf:type sh:PropertyShape triple.
construct: CONSTRUCT { ?propertyShape a sh:PropertyShape . } WHERE { ?shape sh:property ?propertyShape . }
order: 100
prefixes: OWL 2 SHACL semi-closed ruleset

get property shape
type: SPARQLFunction
comment: Gets an existing sh:PropertyShape for a given property at a given shape. If none is found, return a new blank node that will be reused by future calls.
parameter:
  path: predicate
  class: Property
  description: The predicate to match.
parameter:
  path: shape
  class: Shape
  description: The shape hosting the constraint.
prefixes: OWL 2 SHACL semi-closed ruleset
return type: PropertyShape
select: SELECT ?result WHERE { { ?shape sh:property ?result . ?result sh:path ?predicate . } UNION { BIND( IF( CONTAINS(STR(?predicate), '#'), STRAFTER(STR(?predicate), '#'), REPLACE(REPLACE(STR(?predicate), '/', '_'), ':', '_') ) AS ?propertyLocalName ) BIND ( IF(isIRI($shape), IRI(CONCAT( STR($shape), "-", ?propertyLocalName )), BNODE() ) AS ?result) . } }