phax / ph-schematron

Java Schematron library that supports XSLT and native application
Apache License 2.0
110 stars 36 forks source link

Unable to compare attribute with variable (let) #143

Closed FlorianTim closed 6 months ago

FlorianTim commented 1 year ago

Schematron implementation: Pure Module: ph-schematron-pure Versions: 7.1.0, 7.0.1, 7.0.0, 6.3.4, ...

Description: As soon as we compare an attribute with a variable in an expression, the expression evaluates to false although both contain the same value. However, if we compare the variable or value individually with the literal, the expression evaluates correctly to true.

Example: @listName = $list-name // evaluates to false but @listName = 'cpv' // evaluates to true 'cpv'= @listName // evaluates to true

Full Example:

<rule context="/*[$isChangeNotice = true()]/cac:ProcurementProjectLot[cbc:ID/@schemeName='Lot']">
    <let name="lot-id" value="cbc:ID[@schemeName='Lot']/fn:normalize-space(text())"/>
    <let name="list-name" value="cac:ProcurementProject/cac:MainCommodityClassification/cbc:ItemClassificationCode/fn:normalize-space(@listName)"/>

    <let name="parent-cpv2"
         value="$parentNotice/*/cac:ProcurementProjectLot[cbc:ID[@schemeName='Lot']/fn:normalize-space(text()) = $lot-id]/cac:ProcurementProject/cac:MainCommodityClassification/cbc:ItemClassificationCode[@listName = 'cpv']/fn:normalize-space(text())"/>
    <let name="parent-cpv3"
         value="$parentNotice/*/cac:ProcurementProjectLot[cbc:ID[@schemeName='Lot']/fn:normalize-space(text()) = $lot-id]/cac:ProcurementProject/cac:MainCommodityClassification/cbc:ItemClassificationCode['cpv'= @listName]/fn:normalize-space(text())"/>
    <let name="parent-cpv4"
         value="$parentNotice/*/cac:ProcurementProjectLot[cbc:ID[@schemeName='Lot']/fn:normalize-space(text()) = $lot-id]/cac:ProcurementProject/cac:MainCommodityClassification/cbc:ItemClassificationCode[@listName = $list-name]/fn:normalize-space(text())"/>

    <assert role="ERROR"
            test="( cac:ProcurementProject/cac:MainCommodityClassification/cbc:ItemClassificationCode/fn:normalize-space(text()) = $parentNotice/*/cac:ProcurementProjectLot[cbc:ID[@schemeName='Lot']/fn:normalize-space(text()) = $lot-id]/cac:ProcurementProject/cac:MainCommodityClassification/cbc:ItemClassificationCode[@listName = $list-name]/fn:normalize-space(text()) ) or not( $noticeSubType = ('7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '40') )">

        cpv2:
        <value-of select="$parent-cpv2"/>
        cpv3:
        <value-of select="$parent-cpv3"/>
        cpv4:
        <value-of select="$parent-cpv4"/>

        The BT-262 MainCommodityClassification codes for Lot
        <value-of select="$lot-id"/>
        must be the same as for the parent notice.
    </assert>
</rule>
phax commented 1 year ago

I guess this is the same as #88 and #91 ...???

FlorianTim commented 1 year ago

Ok, the issue seems to have the same cause as #88 and #91.

Unfortunately, we are legally bound to the use of the Schematron files.

Is it likely that the bug will be fixed in the near future? Or is there a viable workaround?

Are there any ways to assist in correcting the bug? Maybe there is a unit test or module we can look at.

Thank you very much for your support. :)

phax commented 1 year ago

Well, I would suggest you move from pure to the xslt based version - that one handles the dynamic let parts more correct - of course at the expense of runtime ;-) hth

phax commented 1 year ago

See https://github.com/qligier/Schematronix as a possible way on how to inject variables differently

pigelvy commented 1 year ago

As a follow-up to my recent comment, let's consider the following XML example.

<xml>
  <owner id="o1">
  <car id="c1" owner="o1">

  <owner id="o2">
  <car id="c2" owner="o2">
  <car id="c3" owner="o2">
</xml>

Assuming the usage of the Pure Schematron implementation, I'm wondering how one would write a validation schema that verifies that an owner does not have multiple cars?

The context of the rule could be either /xml/owner or /xml/car and we would have to store the id of the owner in a variable and use its evaluated value in a XPath filter predicate to count the <car> occurences.

With my current understanding, the Schematron schema would look like

<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xpath2">
  <pattern>
    <rule context="/xml/owner">
      <let name="id" value="@id"/>

      <report test="count(/xml/car[@owner eq $id]) gt 1">Owner <value-of select="$id"/> has more than 1 car</report>
    </rule>
  </pattern>
</schema>

or

<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xpath2">
  <pattern>
    <rule context="/xml/car">
      <let name="owner" value="@owner"/>

      <report test="count(/xml/car[@owner eq $owner]) gt 1">Owner <value-of select="$owner"/> has more than 1 car</report>
    </rule>
  </pattern>
</schema>

With this issue, is that kind of validation even possible? Is there a technique or trick that I don't know about? Regards

phax commented 1 year ago

You are right. I will see, that I get it implemented accordingly....

stale[bot] commented 8 months ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

phax commented 6 months ago

Part of the 8.0.0 release - finally :)