- From: Peter F. Patel-Schneider <pfpschneider@gmail.com>
- Date: Sat, 18 Feb 2017 19:17:55 -0800
- To: Holger Knublauch <holger@topquadrant.com>, public-rdf-shapes@w3.org
I spent about an hour yesterday evening looking into building a syntax checker for SHACL Core in non-recursive SHACL Core. It turns out that there is only one problem, and that is checking for loops in property paths and shapes. These loops can be checked if sh:disjoint is generalized to take a path instead of just a property. So here is a syntax checker for a slightly modified version of non-recursive SHACL Core in this slightly extended version of non-recursive SHACL Core. The changes from the current definition of SHACL Core are: 1/ The syntaxt of property paths has been fixed. 2/ There is a simpler setup for shapes, eliminating sh:NodeShape and sh:PropertyShape in favour of sh:Shape and replacing sh:node and sh:property with sh:shape. 3/ The constraint components using sh:equals, sh:disjoint, sh:lessThan, sh:lessThanOrEquals have been extended to permit SHACL paths. 4/ The feature involving sh:disjointSiblings has been removed. 5/ Boolean parameters don't allow multiple values. Having both true and false for a boolean parameter is confusing. 6/ The only lists and property paths that are checked for ill-formedness are those that are used by shapes. Checking other lists and property paths is unnecessary. Well-formed SHACL lists: 1. rdf:nil has no value for rdf:first 2. rdf:nil has no value for rdf:rest 3. Some value for rdf:rest* is rdf:nil 4. Each value for rdf:rest* that is not rdf:nil has single value for rdf:first and single value for rdf:rest. shi:SHACLlist rdf:type sh:Shape ; sh:path [ sh:zeroOrMorePath rdf:rest ] ; sh:hasValue rdf:nil ; sh:or ( [ sh:in ( rdf:nil ) ; sh:shape [ sh:path rdf:first ; sh:maxCount 0 ] ; sh:shape [ sh:path rdf:rest ; sh:maxCount 0 ] . [ sh:shape [ sh:path rdf:first; sh:minCount 1; sh:maxCount 1 ] ; sh:shape [ sh:path rdf:rest; sh:minCount 1; sh:maxCount 1 ] ] ) . Well-formed SHACL property paths: - no loops - either IRI or blank node - if blank node exactly one of the following ; if so extra condition - has >0 rdf:first or >0 rdf:rest ; is SHACL list of property paths, length > 1 - has >0 sh:alternativePath; single value is list of property paths, length > 1 - has >0 sh:inverse; single value is property path - has >0 sh:zeroOrMorePath; single value is property path - has >0 sh:oneOrMorePath; single value is property path - has >0 sh:zeroOrOnePath; single value is property path _:pathPath sh:alternativePath ( [ sh:sequencePath ( [ sh:zeroOrMorePath rdf:rest ] rdf:first ) ] [ sh:sequencePath ( sh:alternativePath [ sh:zeroOrMorePath rdf:rest ] rdf:first ) ] sh:inverse sh:zeroOrMorePath sh:oneOrMorePath sh:zeroOrOnePath ) . shi:pPath rdf:type sh:Shape ; sh:shape [ sh:path [ sh:zeroOrMorePath _:pathPath ] ; sh:shape shi:pPathLocal ] ; sh:disjoint [ sh:oneOrMorePath _:pathPath ] . # no loops shi:pPathLocal rdf:type sh:Shape ; sh:or ( [ sh:nodeKind sh:IRI ] [ sh:nodeKind sh:BlankNode ; sh:shape [ sh:path sh:first ; sh:maxCount 1 ] ; sh:shape [ sh:path sh:rest ; sh:maxCount 1 ; sh:shape shi:SHACLlist ; sh:not [ sh:path rdf:rest ; sh:hasValue rdf:nil ] ] ; sh:shape [ sh:path sh:alternativePath ; sh:maxCount 1 ; sh:shape shi:SHACLlist ; sh:not [ sh:path rdf:resf ; sh:hasValue rdf:nil ] ; sh:not [ sh:path ( rdf:rest rdf:rest ) ; sh:hasValue rdf:nil ] ] ; sh:shape [ sh:path sh:inverse ; sh:maxCount 1 ] ; sh:shape [ sh:path sh:zeroOrMorePath ; sh:maxCount 1 ] ; sh:shape [ sh:path sh:oneOrMorePath ; sh:maxCount 1 ] ; sh:shape [ sh:path sh:zeroOrOnePath ; sh:maxCount 1 ] ; sh:xone ( [ sh:or ( [ sh:path rdf:first ; sh:minCount 1 ] [ sh:path rdf:rest ; sh:minCount 1 ] ) ] ; [ sh:path sh:alternativePath ; sh:minCount 1 ] ; [ sh:path sh:inverse ; sh:minCount 1 ] ; [ sh:path sh:zeroOrMorePath ; sh:minCount 1 ] ; [ sh:path sh:oneOrMorePath ; sh:minCount 1 ] ; [ sh:path sh:zeroOrOnePath ; sh:minCount 1 ] ) ] ) . Shapes: - SHACL instances of sh:Shape - subjects of triples with target property as predicate - subjects of triples with parameter as predicate - objects of triples with non list-taking, shape-expecting parameter as predicate - elements of values of triples with list-taking, shape-expecting parameters as predicate _:subshapePath sh:alternativePath ( sh:not sh:shape ( sh:and [ sh:zeroOrMorePath sh:rest] sh:first ) ( sh:or [ sh:zeroOrMorePath sh:rest] sh:first ) ( sh:xone [ sh:zeroOrMorePath sh:rest] sh:first ) ) . shi:shapes rdf:type sh:Shape ; sh:targetClass sh:Shape ; sh:targetSubjectsOf sh:targetClass , sh:targetNode , sh:targetSubjectsOf , sh:targetObjectsOf ; sh:targetSubjectsOf sh:class, sh:datatype, sh:nodeKind, sh:minCount, sh:maxCount, sh:minExclusive, sh:minInclusive, sh:maxExclusive, sh:maxInclusive, sh:minLength, sh:maxLength, sh:pattern, sh:flags, sh:languageIn, sh:uniqueLang, sh:equals, sh:disjoint, sh:lessThan, sh:lessThanOrEquals, sh:qualifiedValueShape, sh:qualifiedMinCount, sh:qualifiedMaxCount, sh:closed, sh:ignoredProperties, sh:in, sh:hasValue ; sh:targetObjectsOf sh:not, sh:shape, sh:qualifiedValueShape ; sh:shape shi:shape . shi:shapeLists rdf:type sh:Shape ; sh:targetObjectsOf sh:and, sh:or, sh:xone ; sh:shape shi:SHACLlist ; sh:shape [ sh:path ( [ sh:zeroOrMorePath rdf:rest ] rdf:first ); sh:shape shi:shape ] . Well-formed shapes: - no recursive shapes _:shapepath sh:alternativePath ( sh:shape sh:qualifiedValueShape ( [ sh:alternativePath ( sh:and sh:or sh:xone ) ] [ sh:zeroOrMorePath rdf:rest ] rdf:first ) ) . shi:shape rdf:type sh:Shape ; sh:shape [ sh:path [ sh:zeroOrMorePath_:shapepath ] ; shi:shapeLocal ] ; sh:disjoint [ sh:oneOrMorePath _:shapepath ] . # remove to allow recursive shapes Targets in well-formed shapes: - sh:targetNode - IRI or literal - sh:targetClass - IRI - sh:targetSubjectsOf, sh:targetObjectsOf - IRI shi:shapeLocal rdf:type sh:Shape ; sh:shape [ sh:path sh:targetNode ; sh:nodeKind sh:IRIOrLiteral ] ; sh:shape [ sh:path sh:targetClass ; sh:nodeKind sh:IRI ] ; sh:shape [ sh:path sh:targetSubjectsOf ; sh:nodeKind sh:IRI ] ; sh:shape [ sh:path sh:targetObjectsOf ; sh:nodeKind sh:IRI ] . Implicit target in well-formed shapes: - SHACL instance of both sh:Shape and rdfs:Class must be IRI shi:shapeLocal sh:or ( [ sh:not [ sh:class rdfs:Class ; sh:class sh:Shape ] ] ; [ sh:nodeKind sh:IRI ] ) . Property values in well-formed shapes: - sh:Severity - IRI - sh:deactivated - **at most one** - datatype xsd:boolean - sh:path - at most one value - SHACL property path - sh:class - IRI - sh:datatype - IRI - sh:nodeKind - sh:IRI, .... - sh:minCount, sh:maxCount - datatype xsd:integer - sh:minExclusive, sh:minInclusive - literal - sh:maxExclusive, sh:maxInclusive - literal - sh:minLength, sh:maxLength - datatype xsd:integer - sh:pattern, sh:flags - at most one, datatype xsd:string - sh:languageIn - SHACL list of datatype xsd:string - sh:uniqueLang - **at most one**, xsd:boolean - sh:equals, sh:disjoint, sh:lessThan, sh:lessThanOrEquals - path (was IRI) - sh:not, sh:shape, (sh:node, sh:property) - shape - sh:and, sh:or, sh:xone - SHACL list of shapes - sh:qualifiedValueShape - at most one - shape - sh:qualifiedMaxCount, sh:qualifiedMinCount - at most one - datatype xsd:integer - sh:in - SHACL list - sh:hasValue - no restrictions - sh:closed - at most one, xsd:boolean - sh:ignoredProperties - at most one, SHACL list of IRI shi:shapeLocal sh:shape [ sh:path sh:Severity ; sh:nodeKind sh:IRI ] ; sh:shape [ sh:path sh:deactivated ; sh:maxCount 1; sh:datatype xsd:boolean ] ; sh:shape [ sh:path sh:path ; sh:maxCount 1; sh:shape shi:pPath ] ; sh:shape [ sh:path sh:class ; sh:nodeKind sh:IRI ] ; sh:shape [ sh:path sh:datatype ; sh:nodeKind sh:IRI ] ; sh:shape [ sh:path sh:nodeKind ; sh:in ( sh:BlankNode sh:IRI sh:Literal sh:BlankNodeOrIRI sh:BlankNodeOrLiteral sh:IRIOrLiteral ) ] ; sh:shape [ sh:path sh:minCount ; sh:datatype xsd:integer ] ; sh:shape [ sh:path sh:maxCount ; sh:datatype xsd:integer ] ; sh:shape [ sh:path sh:minExclusive ; sh:nodeKind sh:Literal ] ; sh:shape [ sh:path sh:minInclusive ; sh:nodeKind sh:Literal ] ; sh:shape [ sh:path sh:maxExclusive ; sh:nodeKind sh:Literal ] ; sh:shape [ sh:path sh:maxInclusive ; sh:nodeKind sh:Literal ] ; sh:shape [ sh:path sh:minLength ; sh:datatype xsd:integer ] ; sh:shape [ sh:path sh:maxLength ; sh:datatype xsd:integer ] ; sh:shape [ sh:path sh:pattern ; sh:maxCount 1 ; sh:datatype xsd:string ] ; sh:shape [ sh:path sh:flags ; sh:maxCount 1 ; sh:datatype xsd:string ] ; sh:shape [ sh:path sh:languageIn ; sh:shape shi:SHACLlist ; sh:shape [ sh:path ( [ sh:zeroOrMorePath rdf:rest) rdf:first ) ; sh:datatype xsd:string ] ] ; sh:shape [ sh:path sh:uniqueLang ; sh:maxCount 1; sh:datatype xsd:boolean ] ; sh:shape [ sh:path sh:equals ; sh:shape shi:pPath ] ; # was sh:nodeKind sh:IRI sh:shape [ sh:path sh:disjoint ; sh:shape shi:pPath ] ; # was sh:nodeKind sh:IRI sh:shape [ sh:path sh:lessThan ; sh:shape shi:pPath ] ; # was sh:nodeKind sh:IRI sh:shape [ sh:path sh:lessThanOrequals ; sh:shape shi:pPath ] ; # was sh:nodeKind sh:IRI sh:shape [ sh:path sh:qualifiedValueShape ; sh:maxCount 1 ] ; sh:shape [ sh:path sh:qualifiedMinCount ; sh:maxCount 1 ] ; sh:shape [ sh:path sh:qualifiedMaxCount ; sh:maxCount 1 ] ; sh:shape [ sh:path sh:closed ; sh:maxCount 1; sh:datatype xsd:boolean ] ; sh:shape [ sh:path sh:ignoredProperties ; sh:maxCount 1; sh:shape shi:SHACLlist ; sh:shape [ sh:path ( [ sh:zeroOrMorePath sh:rest ] sh:first ) ; sh:nodeKind sh:IRI ] ] ; sh:shape [ sh:path sh:in ; sh:shape shi:SHACLlist ] . Peter F. Patel-Schneider Nuance Communications
Received on Sunday, 19 February 2017 03:18:34 UTC