I'm trying to enforce a uniqueness constraint in an XForm binding. The relevant XML instance snippet is:
<PortAssignments>
<PortAssignment>
<PortReference IDREF="A">
<PortReference IDREF="1">
<Value>FOO</Value>
</PortAssignment>
<PortAssignment>
<PortReference IDREF="A">
<PortReference IDREF="1">
<Value>BAR</Value>
</PortAssignment>
<PortAssignment>
<PortReference IDREF="B">
<PortReference IDREF="2">
<Value>FOO2</Value>
</PortAssignment>
</PortAssignments>
The constraint is that each port can only be connected to one other unique port, so in this case, A must always be connected to 1, and B must always be connected to 2. But, because they don't have to be unique in total, I can't simply check that there are no repeats, so a binding like the following doesn't work.
<xf:bind ref="PortReference">
<xf:bind ref="@IDREF" required="true" type="xs:string" constraint="not(. = ../../preceding-sibling::*/PortReference/@IDREF) and not(. = ../../following-sibling::*/PortReferenence/@IDREF)"/>
</xf:bind>
The other thing I've tried is comparing the second PortReference in the binding to the second PortReference in the PortAssignment with the matching IDREF, but I can't figure out a way to include the context from the current node. An example of that type of lookup is:
<xf:bind ref="PortReference">
<xf:bind ref="@IDREF" required="true" type="xs:string" constraint="not(../../../PortAssignment[PortReference/@IDREF = {binding node's IDREF}][rest of comparison])"/>
</xf:bind>
After seeing Bill's answer talking about the context()
function, I looked around and found this discussion and realized I could use the current()
function for my {binding node's IDREF}
. This lead to the following XPath, which worked for any number of matching PortReferences.
<xf:bind ref="PortAssignment/PortReference/@IDREF" constraint="not(boolean(../../preceding-sibling::*[PortReference[1]/@IDREF = current() and PortReference[2]/@IDREF != current()/../../PortReference[2]/@IDREF])) and not(boolean(../../following-sibling::*[PortReference[1]/@IDREF = current() and PortReference[2]/@IDREF != current()/../../PortReference[2]/@IDREF]))"/>