w3c / shacl

SHACL Community Group (Post-REC activitities)
27 stars 4 forks source link

shaclc grammar: nodeOr vs propertyOr #12

Open VladimirAlexiev opened 2 years ago

VladimirAlexiev commented 2 years ago

I want to implement a constraint "Each SKOS Concept must either have skos:topConcept pointing to the nom: scheme, or have a parent that's in the same scheme". I have 2 problems:

The best I can come up with is this:

shape nomShape:concept {
  skos:topConceptOf|skos:broader  hasValue=nom:|@nomShape:parentConcept
    message="Concepts must either have skos:topConcept pointing to the nom: scheme, or have a parent that's in the same scheme"
    [1..1].
}

The first | is an alternative prop path, and the second | is propertyOr. So this says "Each concept must have topConceptOf or broader, and the value must be either the nom: scheme, or satisfy nomShape:parentConcept", and is correctly translated to this SHACL:

        sh:property          [ sh:maxCount  1 ;
                               sh:message   "Concepts must either have skos:topConcept pointing to the nom: scheme, or have a parent that's in the same scheme" ;
                               sh:minCount  1 ;
                               sh:or        ( [ sh:hasValue  nom: ]
                                              [ sh:node  nomShape:parentConcept ]
                                            ) ;
                               sh:path      [ sh:alternativePath  ( skos:topConceptOf skos:broader ) ]
                             ] ;

But it doesn't preclude the mixed-up variants skos:broader nom: or skos:topConceptOf <parentConcept>.

What I want is shaclc grammar that can produce this shacl:

sh:message   "Concepts must either have skos:topConcept pointing to the nom: scheme, or have a parent that's in the same scheme" ;
sh:or (
    [sh:property [sh:path skos:topConceptOf; sh:maxCount 1; sh:minCount 1; sh:hasValue  nom: ]]
    [sh:property [sh:path skos:broader; sh:maxCount 1; sh:minCount 1; sh:node  nomShape:parentConcept]]);

@HolgerKnublauch Can you help?

HolgerKnublauch commented 2 years ago

I have no strong opinion here, neither do I "own" this language.

There is the usual trade-off between keeping the language simple and adding greater expressiveness. SHACLC is not meant to cover all possible SHACL design patterns.

Do you have a proposal for how the SHACLC should look like to cover your use case? Does ShEx have something similar that we could borrow?

afs commented 2 years ago

Is there any technical reason SHACLC++ can't cover all SHACL expressions?

xone isn't primitive: A xone B = (A and (not B)) or ((not A) and B).

Can that be used to write it in SHACL? (yes, with the duplication, and using refs to node shapes).

ShEx has "OneOf", which is | within tripleExpressions, because triples are matched and assigned to partitions, not "used twice". It also has "OR"/"AND"/"NOT".

HolgerKnublauch commented 2 years ago

I see no technical obstacles, only that any such coverage of all SHACL features may converge towards a Turtle-like syntax. Yes we could come up with more special syntax such as an xone operator but at some stage I wonder why people would prefer to learn all these details if they already have a generic and consistent solution with Turtle, which can also express non-SHACL triples.

jeswr commented 2 years ago

only that any such coverage of all SHACL features may converge towards a Turtle-like syntax.

In a SHACLC parser that I was working on a while back, I had was adding the option to 'escape' (using a backslash IIRC) into Turtle to add anything that was not covered by the existing SHACLC spec - so that is another way to get full SHACL spec coverage with minimal implementation overhead as one can just make use of existing Turtle syntax parsers.

For reference this is the implementation - planning on coming back to finish it up in a month or two WIP SHACLC Parser: https://github.com/jeswr/shaclcjs WIP SHACLC Writer: https://github.com/jeswr/shaclc-writer

HolgerKnublauch commented 2 years ago

@jeswr Yes I did something similar a while back for GraphQL support. Basically, GraphQL has its own schema language that is less expressive than SHACL. So in my converter from SHACL to GraphQL schema, I ticked off all triples that it was able to convert to GraphQL built-ins and then added an escape mechanism to append a Turtle snippet for "all other" triples.

VladimirAlexiev commented 2 years ago

@HolgerKnublauch Can a syntax like this work?

shape nomShape:concept {
  ( skos:topConceptOf hasValue=nom: [1..1]
  |
  skos:broader @nomShape:parentConcept [1..1]
  ) message="Concepts must either have skos:topConcept pointing to the nom: scheme, or have a parent that's in the same scheme".  
}

at some stage I wonder why people would prefer to learn all these details if they already have a generic and consistent solution with Turtle

Because when doing modeling, people want to concentrate on the model, not the syntax. So a syntax that's 10x briefer is much preferable to a heavier syntax. Just like:

@afs SHEX References:

You're right that "xone isn't primitive" but

afs commented 2 years ago

What's missing: the generality of logic operators on shapes. SHACL-C has a fixed OR-AND structure which covers the most common case.

  1. The logical set of operations on node shapes in the AST: nodeAnd, nodeXOne, nodeOr, nodeNot
  2. nodeAtom for nodeShapes, which is "nodeValue | ref | {...}" for nesting control
  3. Probably aligning property shapes to the same structure; they already do nest with {...} within the fixed layout form
  4. Align naming

@VladimirAlexiev --