Using Qualified Value Shapes on Forms - What to expect?

18 views
Skip to first unread message

Tim Smith

unread,
Oct 11, 2022, 5:45:18 PM10/11/22
to topbrai...@googlegroups.com
Hi,

I have a need to use the same property to point to instances of different classes via different property shapes.  I am attempting to use Qualified Value Shapes to support this use case which is similar to the second example found here.

The attached zip file contains my example as discussed below.

I declare a class, Thing with QVS, with two property shapes using the :composedOf property to specify that one shape should point to an instance of Class 1 and the other to Class 2.

When I create an instance of Thing with QVS, I was expecting to see both shapes on the form, but I only see the first one.

image.png

When I put the form in edit mode, it does not offer type ahead or the ability to create a new instance.  The field is only defined as a text field.

image.png

There are two versions of the class definition.  The first one below is my manual editing to create the QVS's which is what is in the attached zip file..  The second version was created using the QVS editing panel.  The results are the same.

Am I confused about how QVS's are to be handled in the form system?

Thanks in advance for your help,

Tim

Manually created QVSs:

qvs_test:ThingWithQVS
  a owl:Class ;
  a sh:NodeShape ;
  rdfs:label "Thing With QVS" ;
  rdfs:subClassOf owl:Thing ;
  sh:property qvs_test:ThingWithQVS-composedOf-1 ;
  sh:property qvs_test:ThingWithQVS-composedOf-2 ;
.
qvs_test:ThingWithQVS-composedOf-1
  a sh:PropertyShape ;
  sh:path qvs_test:composedOf ;
  sh:name "Class 1"@en ;
  sh:qualifiedMaxCount 1 ;
  sh:qualifiedMinCount 0 ;
  sh:qualifiedValueShape [
      sh:class qvs_test:Class1 ;
    ] ;
  sh:qualifiedValueShapesDisjoint true ;
.
qvs_test:ThingWithQVS-composedOf-2
  a sh:PropertyShape ;
  sh:path qvs_test:composedOf ;
  sh:name "Class 2"@en ;
  sh:qualifiedMaxCount 1 ;
  sh:qualifiedMinCount 0 ;
  sh:qualifiedValueShape [
      sh:class qvs_test:Class2 ;
    ] ;
  sh:qualifiedValueShapesDisjoint true ;
.

EDG UI create QVSs

qvs_test:ThingWithQVS
  a owl:Class ;
  a sh:NodeShape ;
  rdfs:label "Thing With QVS" ;
  rdfs:subClassOf owl:Thing ;
  sh:property [
      a sh:PropertyShape ;
      sh:path qvs_test:composedOf ;
      sh:message "Must have at least 1 and at most 1 values of type Class 1" ;
      sh:name "Class 1" ;
      sh:qualifiedMaxCount 1 ;
      sh:qualifiedMinCount 1 ;
      sh:qualifiedValueShape [
          sh:class qvs_test:Class1 ;
        ] ;
    ] ;
  sh:property [
      a sh:PropertyShape ;
      sh:path qvs_test:composedOf ;
      sh:message "Must have at least 1 and at most 1 values of type Class 2" ;
      sh:name "Class 2" ;
      sh:qualifiedMaxCount 1 ;
      sh:qualifiedMinCount 1 ;
      sh:qualifiedValueShape [
          sh:class qvs_test:Class2 ;
        ] ;
    ] ;
.
data_qvs_test.zip

Holger Knublauch

unread,
Oct 12, 2022, 4:37:30 AM10/12/22
to topbrai...@googlegroups.com
Hi Tim,

the general problem with QVS is that they never define an absolute statement about ALL values. So whatever you specify, the property may still have other values (e.g. strings) unless you add sh:class and sh:datatype constraints. This has some implications on the UI.

The form only ever displays one widget for each property (sh:path). So you wouldn't get two different input fields.

The form therefore cannot limit the input fields to either of the two QVS branches, because it cannot know which one you were planning to enter next.

The form does use the QVS (or any non-UI constraint) for validation, so you'd get the error messages.

The form also uses sh:class and sh:datatype to select the widgets. In your case, you may want to use sh:class owl:Thing to at least point at the highest common superclass of Class1 and Class2.

Then you'd at least get this UIX:


For this (sub-optimal) solution I onlyl added the sh:class constraint, removed the extra sh:names and added human-readable sh:message:

qvs_test:ThingWithQVS
  a owl:Class ;
  a sh:NodeShape ;
  rdfs:label "Thing With QVS" ;
  rdfs:subClassOf owl:Thing ;
  sh:property qvs_test:ThingWithQVS-composedOf ;
  sh:property qvs_test:ThingWithQVS-composedOf-1 ;
  sh:property qvs_test:ThingWithQVS-composedOf-2 ;
.
qvs_test:ThingWithQVS-composedOf
  a sh:PropertyShape ;
  sh:path qvs_test:composedOf ;
  sh:class owl:Thing ;
  sh:name "composed of" ;
.
qvs_test:ThingWithQVS-composedOf-1
  a sh:PropertyShape ;
  sh:path qvs_test:composedOf ;
  sh:qualifiedMaxCount 1 ;
  sh:qualifiedMinCount 1 ;
  sh:qualifiedValueShape [
      sh:class qvs_test:Class1 ;
    ] ;
  sh:qualifiedValueShapesDisjoint true ;
  sh:message "One value must be instance of Class 1" ;
.
qvs_test:ThingWithQVS-composedOf-2
  a sh:PropertyShape ;
  sh:path qvs_test:composedOf ;
  sh:qualifiedMinCount 1 ;
  sh:qualifiedMaxCount 1 ;
  sh:qualifiedValueShape [
      sh:class qvs_test:Class2 ;
    ] ;
  sh:qualifiedValueShapesDisjoint true ;
  sh:message "One value must be instance of Class 2" ;
.

Another approximation would be to add a sh:node constraint in addition to the sh:class. This would make sure that all values are instances of either Class1 or Class2. The auto-complete widget will understand sh:node constraints and filter the instances of the provided sh:class accordingly:


The above can be achieved through:

qvs_test:ThingWithQVS-composedOf
  a sh:PropertyShape ;
  sh:path qvs_test:composedOf ;
  sh:class owl:Thing ;
  sh:name "composed of" ; sh:minCount 2 ; sh:maxCount 2 ;
  sh:node [ sh:or (
      [
        sh:class qvs_test:Class2 ;
      ]
      [
        sh:class qvs_test:Class1 ;
      ]
  ) ] ;
.

If that still doesn't satisfy your expectations from a UIX perspective, you'd need to define two different properties with distinct sh:paths. You could then use a sh:values rule to infer the composedOf triples:


qvs_test:ThingWithQVS
  a owl:Class ;
  a sh:NodeShape ;
  rdfs:label "Thing With QVS" ;
  rdfs:subClassOf owl:Thing ;
  sh:property qvs_test:ThingWithQVS-composedOf ;
  sh:property qvs_test:ThingWithQVS-composedOf-1 ;
  sh:property qvs_test:ThingWithQVS-composedOf-2 ;
.
qvs_test:ThingWithQVS-composedOf
  a sh:PropertyShape ;
  sh:path pgont:composedOf ;
  sh:name "composed of"@en ;
  sh:values [
      sh:path [
          sh:alternativePath (
              pgont:composedOf-1
              pgont:composedOf-2
            ) ;
        ] ;
    ] ;
.
qvs_test:ThingWithQVS-composedOf-1
  a sh:PropertyShape ;
  sh:path pgont:composedOf-1 ;
  sh:class qvs_test:Class1 ;
  sh:maxCount 1 ;
  sh:minCount 0 ;
  sh:name "Class 1"@en ;
.
qvs_test:ThingWithQVS-composedOf-2
  a sh:PropertyShape ;
  sh:path pgont:composedOf-2 ;
  sh:class qvs_test:Class2 ;
  sh:maxCount 1 ;
  sh:minCount 0 ;
  sh:name "Class 2"@en ;
.

This would allow you to still query the composedOf property (using GraphQL or ADS scripts). The UI uses GraphQL to display forms, but you could mark that property hidden to only have the two other input fields on the form.


You could also always asset the inferences for downstream systems that don't understand sh:values rules.

HTH
Holger



On 11 Oct 2022, at 11:45 pm, Tim Smith <smith...@gmail.com> wrote:

Hi,

I have a need to use the same property to point to instances of different classes via different property shapes.  I am attempting to use Qualified Value Shapes to support this use case which is similar to the second example found here.

The attached zip file contains my example as discussed below.

I declare a class, Thing with QVS, with two property shapes using the :composedOf property to specify that one shape should point to an instance of Class 1 and the other to Class 2.

When I create an instance of Thing with QVS, I was expecting to see both shapes on the form, but I only see the first one.

<image.png>

When I put the form in edit mode, it does not offer type ahead or the ability to create a new instance.  The field is only defined as a text field.


--
You received this message because you are subscribed to the Google Groups "TopBraid Suite Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to topbraid-user...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/topbraid-users/CAF0WbnLHHQFDgQ%2BLM4Y2Cwk1cq_axuBHnwiLbU4b61HHWa2muw%40mail.gmail.com.
<data_qvs_test.zip>

Tim Smith

unread,
Oct 20, 2022, 10:45:37 AM10/20/22
to topbrai...@googlegroups.com
Hi Holger,

Thank for all of the options.  I have implemented the direct property with inferred :composedOf relationships to keep my work moving.

Would it be possible, in the case of QV shapes, to generate one input field for each QV property shape? Would this allow the form engine to use the QVS to appropriately limit the input values and enable the creation of new instances?

Thanks,

Tim

Holger Knublauch

unread,
Oct 20, 2022, 10:50:00 AM10/20/22
to topbrai...@googlegroups.com

On 20 Oct 2022, at 4:45 pm, Tim Smith <smith...@gmail.com> wrote:

Hi Holger,

Thank for all of the options.  I have implemented the direct property with inferred :composedOf relationships to keep my work moving.

Would it be possible, in the case of QV shapes, to generate one input field for each QV property shape? Would this allow the form engine to use the QVS to appropriately limit the input values and enable the creation of new instances?

No, we don't have plans for that. It would break too many assumptions of how the current editor works.

Holger



Thanks,

Tim

On Wed, Oct 12, 2022 at 4:37 AM Holger Knublauch <hol...@topquadrant.com> wrote:
Hi Tim,

the general problem with QVS is that they never define an absolute statement about ALL values. So whatever you specify, the property may still have other values (e.g. strings) unless you add sh:class and sh:datatype constraints. This has some implications on the UI.

The form only ever displays one widget for each property (sh:path). So you wouldn't get two different input fields.

The form therefore cannot limit the input fields to either of the two QVS branches, because it cannot know which one you were planning to enter next.

The form does use the QVS (or any non-UI constraint) for validation, so you'd get the error messages.

The form also uses sh:class and sh:datatype to select the widgets. In your case, you may want to use sh:class owl:Thing to at least point at the highest common superclass of Class1 and Class2.

Then you'd at least get this UIX:

<PastedGraphic-2.png>
<PastedGraphic-3.png>
<PastedGraphic-4.png>
Reply all
Reply to author
Forward
0 new messages