- From: Scott Henninger <scotthenninger@gmail.com>
- Date: Wed, 15 Sep 2021 16:30:08 -0500
- To: "public-shacl@w3.org" <public-shacl@w3.org>
- Message-ID: <CAJ-KvVqNUiurF_aZbzJ6ksFqGpF19qA0GPfd8r4H0MQUvvDS-g@mail.gmail.com>
Unfortunately, SHACL-AF is not available to thei system. I have asked for an enhancement to include SHACL-AF, but in the meantime I'm stuck with SHACL only. -- Scott On Wed, Sep 15, 2021 at 4:56 AM Sommer, Ashley (L&W, Dutton Park) < Ashley.Sommer@csiro.au> wrote: > Hi Again Scott, > > After thinking about this for a bit, (I admit I still don't quite > understand what exactly you're trying to achieve) I believe I have found > three different solutions to solve your requirements, with the given Cases.? > The *best *solution I think would be an Expression Constraint from the > SHACL Advanced Features spec (SHACL-AF) in particular, using the > FilterShape > <https://www.w3.org/TR/shacl-af/#node-expressions-filter-shape> > expression. You can also do this with SHACL Rules (again from SHACL-AF). > However first, here is a solution without any advanced features, using > just combinational logic: > > my_sh:ClassShape > a sh:NodeShape ; > sh:targetClass ex:Cls1 ; > sh:message "Should not be a violation" ; > sh:xone ( [ sh:and ( my_sh:PreReqClasses my_sh:MustHaveAName ) ] > [ sh:not my_sh:PreReqClasses ] > ) . > > my_sh:PreReqClasses > a sh:NodeShape ; > sh:property [ sh:path ex:parent ; sh:minCount 1 ; sh:maxCount 1 ] ; > sh:xone ( [sh:path ex:parent ; sh:class ex:P_cls1 ] > [sh:path ex:parent ; sh:class ex:P_cls2 ] > [sh:path ex:parent ; sh:class ex:P_cls3 ] > ) . > > my_sh:MustHaveAName > a sh:PropertyShape ; > sh:path ex:name ; > sh:minCount 1 ; > sh:maxCount 1 ; > sh:message "Instance of targeted class must have one and only one > ex:name" ; . > > This has two disadvantages: a) Running "PreReqClasses" twice, one in the > sh:and, and once in the sh:not, and b) runs MustHaveAName (but doesn't > report errors) even on the nodes which don't meet PreReqClasses. But it > matches the logic you're looking for. > > Now, fun with advanced features: > Firstly an example using SHACLRules: > my_sh:ClassShape > a sh:NodeShape ; > sh:targetClass ex:Cls1 ; > sh:rule [ > a sh:TripleRule ; > sh:subject sh:this ; > sh:predicate rdf:type ; > sh:object ex:ChosenChildren ; > sh:condition my_sh:PreReqClasses ; > ] ; > sh:message "Should not be a violation" ; > . > > my_sh:PreReqClasses > a sh:NodeShape ; > sh:property [ sh:path ex:parent ; sh:minCount 1 ; sh:maxCount 1 ] ; > sh:xone ( [sh:path ex:parent ; sh:class ex:P_cls1 ] > [sh:path ex:parent ; sh:class ex:P_cls2 ] > [sh:path ex:parent ; sh:class ex:P_cls3 ] > ) . > > my_sh:MustHaveAName > a sh:NodeShape ; > sh:targetClass ex:ChosenChildren ; > sh:property [ > sh:path ex:name ; > sh:minCount 1 ; > sh:maxCount 1 ; > sh:message "Instance of targeted class must have one and only one > ex:name" ; > ] . > > This uses a TripleRule <https://www.w3.org/TR/shacl-af/#TripleRule> to > add a new temporary rdf type identifier to the nodes objects in the > datagraph that match the prerequisite condition. > This allows the validator to then subsequently run the MustHaveAName shape > with the targetClass being that new type. > > Finally, as I mentioned up the top, was trying to get an example working > using ExpressionConstraints > <https://www.w3.org/TR/shacl-af/#ExpressionConstraintComponent> > (particularly FilterShape > <https://www.w3.org/TR/shacl-af/#node-expressions-filter-shape>) but it > seems you can only pass the filtered nodes into a SHACL Function, not into > a SHACL Constraint. > Anyway, I hope those examples helped. > > - Ashley > > > > > > ------------------------------ > *From:* Scott Henninger <scotthenninger@gmail.com> > *Sent:* Wednesday, 15 September 2021 1:44 PM > *To:* public-shacl@w3.org <public-shacl@w3.org> > *Subject:* Re: SHACL Shape definition for including and excluding parent > types > > Thanks for the detailed analysis, Ashley. It gave me some insights. > However, I'm guilty of not expressing the problem correctly. The main > requirements are that 1) the target is ex:Cls1 and 2) the ex:parent is 3) > one of n classes, which I have arbitrarily named ex:P_Cls{1, 2, 3}. But > these are intended not as constraints but as a prerequisite. I.e. if the > three are met, then there is a set of constraints that can be evaluated - > such as ex:Cls1 must have one ex:name property. Otherwise the constraints > are ignored. > > So let me start over with some examples. > > Case 1. Adding the constraint that the target class must have an ex:name, > the following is valid for both the class and property constraints. > ex:Child1 > a ex:Cls1 ; > ex:parent ex:Parent1 ; > ex:name "John" . > ex:Parent1 > a ex:P_cls1 . > > Case 2. This is invalid because the ex:name is missing. > ex:Child1 > a ex:Cls1 ; > ex:parent ex:Parent1 . > ex:Parent1 > a ex:P_cls2 . > > Case 3. This is valid because the parent is not in ex:P_Cls{1, 2, 3} and > therefore no shapes are applied. > ex:Child1 > a ex:Cls1 ; > ex:parent ex:Parent1 . > ex:Parent1 > a ex:P_cls_x . > > That to me is the challenging part. I need to express that the three main > requirements are present before the other constraints can be validated. > I.e. the three main requirements (above 1), 2), 3) ) are prerequisites for > applying other shapes. > > Here's an attempt that does some of this (and taking your advice not to > overthink). The only problem is that I do not want a violation on the > class defs. > my_sh:ClassShape > a sh:NodeShape ; > sh:targetClass ex:Cls1 ; . > sh:xone ( [sh:path ex:parent ; sh:class ex:ex:P_cls1 ] > [sh:path ex:parent ; sh:class ex:ex:P_cls2 ] > [sh:path ex:parent ; sh:class ex:ex:P_cls3 ] > ) ; > sh:message "Should not be a violation" ; > sh:property my_sh:MustHaveAName . > > my_sh:MustHaveAName > a sh:PropertyShape ; > sh:path ex:name ; > sh:minCount 1 ; > sh:maxCount 1 ; > sh:message "Instance of targeted class must have one and only one > ex:name" . > > What I would want this to expressis that only Case 2 should cause a > violation. > > Sorry for bungling the initial question (and thanks again for a thorough > response). I'm not entirely sure whether or how SHACL could satisfy this > kind of "prerequisite" constraint. The above fails, as it will throw a > violation if the parent is not one of ex:P_cls{1, 2, 3}. If anyone has > ideas on how to avoid this, I'm all ears. > > Let me know if anything isn't clear or is incorrect (thanks for catching > my sh:not inside of sh:or mistake, BTW). > > Thanks again for taking a look and helping out. > -- Scott > > On Tue, Sep 14, 2021 at 6:44 PM Sommer, Ashley (L&W, Dutton Park) < > Ashley.Sommer@csiro.au> wrote: > > Hi Scott, > > I think you're over thinking this. From what I can tell, you have a simple > requirement. > > Firstly, an obvious error: You have your sh:not constraint in your list of > sh:or options. > So you're effectively saying "class is P_cls1 OR P_cls2 OR P_cls3 OR NOT > ex:P_clsInvalid_a" which as you can see is not logically consistent, > because it would pass for *any* parent class that is > NOT ex:P_clsInvalid_a. > You instead need an AND in there, like "(class is P_cls1 OR P_cls2 > OR P_cls3) AND (NOT ex:P_clsInvalid_a)" like this: > sh:and ( > [ > sh:or ( > [ sh:class ex:P_cls1 ] > [ sh:class ex:P_cls2 ] > [ sh:class ex:P_cls3 ] > ) > ] > [ sh:not [ sh:class ex:P_clsInvalid_a ] ] > ) > > Secondly, to match one and only one of those in the OR list, use > exclusive-or logic (sh:xone in SHACL > <https://www.w3.org/TR/shacl/#XoneConstraintComponent>). Like this: > sh:xone ( > [ sh:class ex:P_cls1 ] > [ sh:class ex:P_cls2 ] > [ sh:class ex:P_cls3 ] > ) ; > > Next, if you want to maintain a list of invalid options, you can use sh:in > <https://www.w3.org/TR/shacl/#InConstraintComponent> wrapped in a sh:not, > to make a "not in" constraint. Like this: > sh:not [ sh:in ( ex:P_clsInvalid_a ex:P_clsInvalid_b ) ] ; > > But when you break it down that far, why do you need the NOT? Wouldn't > just "(class is P_cls1 XOR P_cls2 XOR P_cls3)" do the trick? Anything > with a parent not in that list will be invalid, why does there need to be > invalid classes specified, unless those invalid class are subclasses of > P_cls1, P_cls2, P_cls3 ? > Or are there other unspecified parent classes which are not in the list of > three possible required, but also not invalid? If that is the case, your > requirements need to be restated like: > > - path ex:parent will have only one value > - the value for ex:parent can have one or more types (classes) > - one of those types needs to be {P_cls1 OR P_cls2 OR P_cls3} > - maximum of one of those types can be {P_cls1, P_cls2, P_cls3} > - parent's types cannot be one of {ex:P_clsInvalid_a, > ex:P_clsInvalid_b} > > You can use qualifiedvalueshape to ensure that at least one of the parents > match the OR constraint, not need to use sh:xone in this case. > Note, to emulate sh:class semantics on value-taking shapes like > qualifiedValueShape and sh:in, I am using the same transitive SHACL > Properly Path as demonstrated in the sh:class docs. > <https://www.w3.org/TR/shacl/#ClassConstraintComponent> > > So, if I were writing a shape to match the requirements above, it would > look like this: > > my_sh:ParentTypeRestriction > a sh:NodeShape ; > sh:targetClass ex:Cls1 ; > sh:property [ > sh:path ex:parent ; > sh:minCount 1 ; > sh:maxCount 1 ; > sh:property [ > sh:path ( rdf:type [ sh:zeroOrMorePath rdfs:subClassOf ] ) ; > sh:minCount 1 ; > sh:qualifiedMinCount 1 ; > sh:qualifiedMaxCount 1 ; > sh:qualifiedValueShape [ > sh:or ( > [ sh:hasValue ex:P_cls1 ] > [ sh:hasValue ex:P_cls2 ] > [ sh:hasValue ex:P_cls3 ] > ) > ] ; > sh:not [ sh:in ( ex:P_clsInvalid_a ex:P_clsInvalid_b ) ] ; > ] ; > sh:message "parent type for ex:Cls1 is not in x:P_cls{1, 2, 3}" ; > ] ; > . > (Tested in PySHACL, using the valid and invalid examples you gave in your > correspondence). > > This may be overkill for your requirements, and I may have misinterpreted > your use-case. But it should at least give you something to work with. > It could be taken even further by doing regex on type names to match > P_cls{1,2,3}, if there is a known pattern they match, but that might be > going too far. > > - Ashley > > ------------------------------ > *From:* Scott Henninger <scotthenninger@gmail.com> > *Sent:* Tuesday, 14 September 2021 3:24 PM > *To:* public-shacl@w3.org <public-shacl@w3.org> > *Subject:* SHACL Shape definition for including and excluding parent types > > I have a couple of scenarios that involve restrictions on classes. Most > of them I can get working, but a couple I'm finding a bit difficult to > figure out. To make it simple, I'll start with the parent type restriction > I'm trying to express. > > The following would be a valid shape as it targets ex:Cls1, specifies a > parent with ex:parent, and the parent has one of the types ex:P_cls{1, 2, > 3}. (In all of these cases the targetClass is ex:Cls1). > ex:Child1 > a ex:Cls1 ; > ex:parent ex:Parent1 ; > . > ex:Parent1 > a ex:Pcls1 ; > . > > This would be an invalid shape because ex:Pcls{1,2,3} types must be > defined for the parent: > ex:Child1 > a ex:Cls1 ; > ex:parent ex:Parent1 ; > . > ex:Parent1 > a ex:P_clsInvalid_a ; > . > > This one is valid because it includes one of ex:Pcls{1,2,3}: > ex:Child1 > a ex:Cls1 ; > ex:parent ex:Parent1 ; > . > ex:Parent1 > a ex:P_cls2, ex:P_clsInvalid_a ; > . > > The fourth is invalid because only one of ex:Pcls{1, 2, 3} is allowed: > ex:Child1 > a ex:Cls1 ; > ex:parent ex:Parent1 ; > . > ex:Parent1 > a ex:P_cls1, ex:P_cls2; > . > > If I could live with a list of disallowed types (for the sake of > maintenance I'd rather say allow only ex:P_cls{1, 2, 3}) then the following > seems to work: > my_sh:ParentTypeRestriction > a sh:NodeShape ; > sh:targetClass ex:Cls1 ; > sh:property[ > s h:path ex:parent ; > sh:or ( > [ sh:class ex:P_cls1 ] > [ sh:class ex:P_cls2 ] > [ sh:class ex:P_cls3 ] > [ sh:not [ sh:class ex:P_clsInvalid_a ] ] > ) ; > sh:message "parent type for ex:Cls1 is not in x:P_cls{1, 2, 3}" ; > ] ; > . > > ..where I include an exhaustive list for sh:not. As stated before, this > isn't the best when the model changes and I need to find all the places > where it needs to be excluded. > > So any ideas on how to 1) improve this shape, or 2) future-proof it for > future additions to the rsf:type list? > > Thanks a bunch for taking a look. > -- Scott > > Scott Henninger > scotthenninger@gmail.com > >
Received on Wednesday, 15 September 2021 21:30:36 UTC