0
votes

In an XForms form, I have a section that repeats with inputs inside of it. There is a dropdown that will populate in each repeated section and no two dropdowns can have the same value selected. Each dropdown must have a unique selection and if there is a duplicate selection between dropdowns in the seperate sections they should become invalid.

This is the idea I am going for

constraint="not(. = instance('my-instance')/repeated-section[Include everything BUT .'s parent]/dropdown)"

Sample Instance Data:

<repeated-section>
     <input1></input1>
     <input2></input2>
     <dropdown></dropdown>
     <input4></input4>
</repeated-section>    
<repeated-section>
     <input1></input1>
     <input2></input2>
     <dropdown></dropdown>
     <input4></input4>
</repeated-section>    
<repeated-section>
     <input1></input1>
     <input2></input2>
     <dropdown></dropdown>
     <input4></input4>
</repeated-section>

This is mainly an XPath filtering question. Is it possible to do what I am asking? I want to compare the current node (lets say the 2nd set of the repeated-section) against all other repeated nodesets (repeated-section 1 and 3), excluding the current nodeset (because if you compare against all including the self, it will of course be compared to as true).

1
ergeron: There are two approaches: using preceding and following axis or using exclusion expression (negating Kaysian method for intersection). A meaninful input sample would allow a complete example. - user357812

1 Answers

1
votes

To simplify things, I assumed that you have just one element for each iteration of the repeat:

<instance>
    <repeated-value>1</repeated-value>
    <repeated-value>2</repeated-value>
    <repeated-value>2</repeated-value>
</instance>

Then the constraint becomes:

<xforms:bind ref="repeated-value" constraint="not(. = (../repeated-value except .))"/>

One trick is in the except keyword, which allows you to build a sequence with all the "other repeat-value". Then you want to know if any of those is equal to the current node, which you do with = operator. Finally, the node is valid, if you can't find another node with the same value, hence the not(). Note that using not(… = …) is not the same as … != …. And here is a full example to try this out:

<xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml"
      xmlns:xforms="http://www.w3.org/2002/xforms"
      xmlns:xxforms="http://orbeon.org/oxf/xml/xforms"
      xmlns:ev="http://www.w3.org/2001/xml-events"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:fr="http://orbeon.org/oxf/xml/form-runner">
    <xhtml:head>
        <xhtml:title>No more than one</xhtml:title>
        <xforms:model>
            <xforms:instance>
                <instance>
                    <repeated-value>1</repeated-value>
                    <repeated-value>2</repeated-value>
                    <repeated-value>2</repeated-value>
                </instance>
            </xforms:instance>
            <xforms:bind ref="repeated-value" constraint="not(. = (../repeated-value except .))"/>
        </xforms:model>
        <xhtml:style type="text/css">
            .xforms-repeat-selected-item-1 { background: transparent }
            .xforms-input { display: block; padding-bottom: .5em  }
        </xhtml:style>
    </xhtml:head>
    <xhtml:body>
        <xforms:repeat ref="repeated-value">
            <xforms:input ref=".">
                <xforms:alert>This value is repeated more than once</xforms:alert>
            </xforms:input>
        </xforms:repeat>
    </xhtml:body>
</xhtml:html>