W3C home > Mailing lists > Public > public-data-shapes-wg@w3.org > June 2016

ISSUE-139: implementing (core) constraint components universally

From: Peter F. Patel-Schneider <pfpschneider@gmail.com>
Date: Thu, 2 Jun 2016 14:19:52 -0700
To: RDF Data Shapes Working Group <public-data-shapes-wg@w3.org>
Message-ID: <6d111e20-2e76-f440-2409-6ebfe800497d@gmail.com>
To think about how a constraint component works universally, it is
sufficient to think about value nodes, which are already defined at the
beginning of Section 4.

So, sh:hasValue is then just that a value node is the given node and
sh:equals is just that the set of value nodes is the same as the set of
values for the focus node for the other property and sh:closed is just that
every value node has no values for disallowed properties and sh:minCount is
just that there are at least n value nodes.


Looking at https://github.com/TopQuadrant/shacl the changes to permit core
constraint components to be used universally appear to be as follows:

1/ Ensure that sh:context has all three relevant values for each constraint
component.  (Of course then sh:context becomes irrelevant and can be
removed.)

2/ For the constraint component for:

sh:closed add
  sh:propertyValidator [
      rdf:type sh:SPARQLSelectValidator ;
      sh:message "Predicate {?unallowed} is not allowed on {?subject} (closed
shape)" ;
      sh:sparql """
		SELECT ?this (?val AS ?subject) ?unallowed ?object
		WHERE {
			{
				FILTER ($closed) .
			}
			$this $predicate ?val .
			?val ?unallowed ?object .
			FILTER (NOT EXISTS {
				GRAPH $shapesGraph {
					$currentShape sh:property/sh:predicate ?unallowed .
				}
			} && (!bound($ignoredProperties) || NOT EXISTS {
				GRAPH $shapesGraph {
					$ignoredProperties rdf:rest*/rdf:first ?unallowed .
				}
			}))
		}
""" ;
Similar for inverse property constraint.
sh:closed should also be implementable using the simple form (like
sh:datatype and sh:minExclusive are).

sh:datatype	add dash:hasDatatype as a value for sh:inversePropertyValidator
sh:datatypeIn	add dash:hasDatatypeIn as a value for sh:inversePropertyValidator

sh:hasValue	add
  sh:nodeValidator [
      rdf:type sh:SPARQLSelectValidator ;
      sh:message "Node is not value {$hasValue}" ;
      sh:sparql """
		SELECT $this
		WHERE {
			FILTER { NOT sameTerm($this,$hasValue) }
		}
		""" ;
    ] ;

sh:disjoint add
  sh:inversePropertyValidator [
      rdf:type sh:SPARQLSelectValidator ;
      sh:message "Inverse of property must not share any values with
{$disjoint}" ;
      sh:sparql """
		SELECT $this ($this AS ?object) $predicate ?subject
		WHERE {
			?subject $predicate $this .
			?subject $disjoint $this  .
		}
		""" ;
    ] ;
  sh:nodeValidator [
      rdf:type sh:SPARQLSelectValidator ;
      sh:message "Node must not be a value of {$disjoint}" ;
      sh:sparql """
		SELECT $this
		WHERE {
			$this $disjoint ?this .
		}
		""" ;
    ] ;

sh:equals add
  sh:inversePropertyValidator [
      rdf:type sh:SPARQLSelectValidator ;
      sh:message "Inverse of property must have same values as {$equals}" ;
      sh:sparql """
		SELECT $this ($this AS ?object) $predicate ?subject
		WHERE {
			{
				?subject $predicate $this .
				FILTER NOT EXISTS {
					?subject $equals $this  .
				}
			}
			UNION
			{
				?subject $equals $this .
				FILTER NOT EXISTS {
					?subject $predicate $this .
				}
			}
		}
		""" ;
    ] ;
  sh:nodeValidator [
      rdf:type sh:SPARQLSelectValidator ;
      sh:message "Node must be a value of {$equals}" ;
      sh:sparql """
		SELECT $this
		WHERE {
			FILTER NOT EXISTS { $this $disjoint $this }
		}
		""" ;
    ] ;

sh:lessThan add
  sh:InversePropertyValidator [
      rdf:type sh:SPARQLSelectValidator ;
      sh:message "Inverse property value is not < value of {$lessThan}" ;
      sh:sparql """
		SELECT $this ($this AS ?object) $predicate ?subject
		WHERE {
			?subject $predicate $this  .
 			$this $lessThan ?object2  .
			FILTER (!(?subject < ?object2)) .
		}
		""" ;
    ] ;
  sh:nodeValidator [
      rdf:type sh:SPARQLSelectValidator ;
      sh:message "Node is not < value of {$lessThan}" ;
      sh:sparql """
		SELECT $this
		WHERE {
			$this $lessThan ?object2 .
			FILTER (!(?this < ?object2)) .
		}
		""" ;
    ] ;

sh:lessThanOrEquals similar

sh:minCount add
  sh:nodeValidator [
      rdf:type sh:SPARQLSelectValidator ;
      sh:message "Node is precisely one value, not {$minCount}" ;
      sh:sparql """
		SELECT $this
		WHERE {
			FILTER ( 1 >= $minCount) .
		}
		""" ;
    ] ;

sh:maxCount similar

sh:maxExclusive	add dash:hasMaxExclusive as a value for
sh:inversePropertyValidator

sh:maxInclusive	add dash:hasMaxInclusive as a value for
sh:inversePropertyValidator

sh:minExclusive	add dash:hasMinExclusive as a value for
sh:inversePropertyValidator

sh:minInclusive	add dash:hasMinInclusive as a value for
sh:inversePropertyValidator

sh:uniqueLang add
  sh:inversePropertyValidator [
      rdf:type sh:SPARQLSelectValidator ;
      sh:message "Language {?lang} used more than once" ;
      sh:sparql """
		SELECT DISTINCT $this ($this AS ?object) $predicate ?lang
		WHERE {
			{
				FILTER ($uniqueLang) .
			}
			?value $predicate $this .
			BIND (lang(?value) AS ?lang) .
			FILTER (bound(?lang) && ?lang != \"\") .
			FILTER EXISTS {
				$this $predicate ?otherValue .
				FILTER (?otherValue != ?value && ?lang = lang(?otherValue)) .
			}
		}
		""" ;
    ] ;
  sh:nodeValidator [
      rdf:type sh:SPARQLSelectValidator ;
      sh:message "A language used more than once on node" ;
      sh:sparql """
		SELECT $this
		WHERE { FILTER ( 1 = 0 )
		}
		""" ;
    ] ;

sh:qualifiedMinCount add
  sh:nodeValidator [
      rdf:type sh:SPARQLSelectValidator ;
      sh:sparql """
		SELECT $this ($this AS ?subject) $predicate ?count ?failure
		WHERE {
			BIND (sh:hasShape(?subject, $valueShape, $shapesGraph) AS ?hasShape) .
			BIND (!bound(?hasShape) AS ?failure) .
			FILTER IF(?failure, true, ?count > IF(?hasShape,1,0))
		}
""" ;
    ] ;

sh:qualifiedMaxCount similar


Note that none of these are difficult to do, particularly when looking at
the another validator for the same component.  This should be true for any
constraint component that can be described as working on the value nodes.  I
think that all constraint components should be describable this way.


peter
Received on Thursday, 2 June 2016 21:20:23 UTC

This archive was generated by hypermail 2.3.1 : Thursday, 2 June 2016 21:20:23 UTC