- From: Peter F. Patel-Schneider <pfpschneider@gmail.com>
- Date: Wed, 2 Mar 2016 16:13:17 -0800
- To: Eric Prud'hommeaux <eric@w3.org>, Karen Coyle <kcoyle@kcoyle.net>, Simon Steyskal <simon.steyskal@wu.ac.at>
- Cc: public-data-shapes-wg@w3.org
A modest proposal for a revamped SHACL syntax This proposal rearranges the SHACL constructs, collapsing constraints and shapes into one construct. The result is a more regular SHACL syntax with a simpler metamodel. A few constructs become a bit more verbose. Syntax The main SHACL construct is a shape (sh:Shape). Shapes have zero or more scopes (triples with the shape as subject and sh:scopeNode, sh:scopeClass, sh:scopePropertyObject, or sh:scopePropertySubject as the predicate), zero or more filters (values of sh:filter) which are themselves shapes, one or more components (triples with the shape as subject and one of the component properties as property, including associated triples as necessary), and can be closed (sh:closed value true, zero or more fillers of sh:ignoredProperty). Note: The shape components might be called constraints. I didn't use constraint so as not to cause confusion with the current constraints in SHACL. The syntax of the various components are: sh:class class ... (various other simple components) sh:pattern pattern Q: How to handle flags? There are several options. sh:equals ( property/path ... property/path ) sh:disjoint ( property/path ... property/path ) sh:lessThan ( property/path ... property/path ) ... (other comparison components) sh:fillers [ sh:property property/path; sh:shape shape ] sh:list shape sh:shape shape sh:and ( shape ... shape ) sh:or ( shape ... shape ) sh:not shape sh:minCard int sh:maxCard int sh:uniqueLang true sh:partition ( shape_1, ..., shape_n ) A property/path is either a property or a list consisting of nodes linked to properties via sh:property or sh:propertyInverse. (Yes, this is a bit unclean.) Note: Qualified cardinalities are replaced by an embedded shape where the embedded shape's filter has the same role as the filler for sh:qualifiedValueShape. A vital aspect of this syntax is that each component of shapes uses exactly one triple with the shape as subject. The sole exception is closure, and closure could be reworked this way as well, but closure is special in the semantics so it is not so bad to make it special in the syntax as well. Examples sh:personShape [ a sh:Shape; sh:scopeClass ex:Person ; sh:fillers [ sh:path name; sh:shape [ a sh:Shape; sh:datatype xs:string ] ] ; sh:fillers [ sh:path child; sh:shape [ a sh:Shape; sh:class ex:Person ] ] ; sh:fillers [ sh:path age; sh:shape [ a sh:Shape; sh:datatype xs:integer; sh:minCount 1 ; sh:maxCount 1 ] ] ] . sh:personShape is satisfied on a graph if all instances of ex:Person have all their stated names be strings, all their stated children belonging to ex:Person, and have exactly one stated age, which is an integer. Note: Combining the path and the shape would shorten the syntax but does complicate the metamodel. Alternatively sh:fillers coud take a two-element list. sh:SJG [ a sh:Shape; sh:scopeClass ex:Person ; sh:filter [ a sh:Shape ; sh:fillers [ sh:path gender; sh:shape [ a sh:Shape; sh:in ( ex:female ) ] ] ]; sh:filter [ a sh:Shape ; sh:fillers [ sh:path ( [ sh:property child ] [ sh:property child ] ) ; sh:shape [ a sh:Shape; sh:minCount 1 ] ] ] ; sh:fillers [ sh:path child ; [ a sh:Shape ; sh:filter [ a sh:Shape ; sh:fillers [ sh:path gender; sh:shape [ a sh:Shape; sh:in ( ex:male ) ] ] ] ; sh:class ex:Professional ] ] ] . sh:SJG is satisfied on a graph if all instances of ex:Person (the scope) and have ex:female as gender (the first filter) and have at least one grandchild (the second filter) have all their male children be instances of ex:Professional. Semantics (ignoring recursion) A graph satisfies a shape if the set of nodes of the graph selected by any scope of the shape satisfies the shape. A sh:scopeNode filler selects that node. A sh:scopeClass filler selects each node in the graph that is an instance of the class. A sh:scopePropertyObject filler selects each node in the graph that is an object for that property. A sh:scopePropertySubject selects each node in the graph that is a subject for that property. A shape satisfies a set of nodes (the input nodes) as follows. The input nodes that satisfy each of the filters of the shape are called in-filter nodes, those that do not are out-of-filter nodes. Some components (those involving sh:shape, sh:and, sh:or, sh:not, sh:minCard, sh:maxCard, sh:uniqueLang, and sh:partition) work on the set of in-filter nodes as a whole. If a component of this kind is not satisfied then each of the in-filter nodes fails to satisfy the shape. Some components (values of sh:class, ..., sh:pattern, sh:fillers) work on each in-filter node independently. Each in-filter node that fails to satisfy one or more of these components fails to satisfy the shape. If the shape is closed an in-filter node fails to satisfy the shape if it has a filler for some property that is neither the path of some component of the shape nor a filler for sh:ignoredProperty. Each in-filter node that does not fail to satisfy the shape is said to satisfy the shape. A shape is satisfied on a set of input nodes if there are no in-filter nodes that fail to satisfy the shape on these input nodes. The components work as follows: sh:class class - the node belongs to class ... sh:pattern pattern - the "name" of the node matches pattern sh:equals ( path ... ) - the node has the same fillers for each path sh:disjoint ( path ... ) - the fillers for the paths are pairwise disjoint sh:lessThan ( path ... ) - the fillers for a path are smaller than the fillers for the next path ... sh:fillers [ sh:path path; sh:shape shape ] - the fillers of path for the node satisfy each shape sh:list shape - the nodes in the list are the transitive-reflexive closure of rdf:rest - each such node has a single filler for rdf:rest, except rdf:nil which has none - each such node has a single filler for rdf:first, except rdf:nil which has none - the nodes that are rdf:first fillers sh:shape shape - the set of in-filter nodes satisfies the shape sh:and ( shape ... shape ) - the set of in-filter nodes satisfies each shape sh:or ( shape ... shape ) - each in-filter node is individually satisfied by some shape, i.e., if there are only sh:class constructs then each in-filter node belongs to one of them or the set of in-filter nodes satisfies some shape, i.e., if there are n fillers and a sh:minCard of n then the sh:or is satisfied sh:not shape - the set of in-filter nodes does not satisfy the shape sh:minCard int - there are at least int in-filter nodes sh:maxCard int - there are at most int in-filter nodes sh:uniqueLang true - only one in-filter node for any particular language tag sh:partition ( shape_1, ..., shape_n ) - let input_1 be the set of in-filter nodes - let input_i+1 be the out-of-filter nodes of shape_i on input_i - shape_i is satisfied on input_i, for 1<=i<=n - input_n+1 is empty Meta model classes and properties - sh:Shape - sh:scopeNode, sh:scopeClass, sh:scopePropertyObject, sh:scopePropertySubject - sh:filter, sh:closed, sh:ignoredProperty - sh:class, ..., sh:pattern, sh:equals, sh:disjoint, sh:lessThan, ..., sh:fillers, sh:list - sh:shape, sh:and, sh:or, sh:not, sh::minCard, sh:maxCard, sh:uniqueLang, sh:partition - sh:property, sh:propertyInverse - sh:severity, sh:name, ...
Received on Thursday, 3 March 2016 00:13:50 UTC