orbeon / orbeon-forms

Orbeon Forms is an open source web forms solution. It includes an XForms engine, the Form Builder web-based form editor, and the Form Runner runtime.
http://www.orbeon.com/
GNU Lesser General Public License v2.1
514 stars 221 forks source link

`model` on `xf:output` inside `xf:label` not taken into account #5304

Open avernet opened 2 years ago

avernet commented 2 years ago

To reproduce, run the form below, and notice label of the field is "1" instead of "2".

+1 from customer

<xh:html xmlns:xh="http://www.w3.org/1999/xhtml"
      xmlns:xf="http://www.w3.org/2002/xforms">
    <xh:head>
        <xf:model>
            <xf:instance>
                <_>1</_>
            </xf:instance>
        </xf:model>
        <xf:model id="2">
            <xf:instance>
                <_>2</_>
            </xf:instance>
        </xf:model>
    </xh:head>
    <xh:body>
        <xf:input ref=".">
            <xf:label>
                <xf:output model="2" ref="."/>
            </xf:label>
        </xf:input>
    </xh:body>
</xh:html>
ebruchez commented 2 years ago

This is a known issue. We no longer support model and xxbl:scope on nested elements within LHHA because we translate the entire LHHA into a single XPath expression.

In this simple case, the workaround is to put the model on <xf:label>.

ebruchez commented 2 years ago
ebruchez commented 2 years ago

If the requirement remains to be able to produce a single expression, I was wondering whether it would be possible to do so and change the model. For this, we need to be able to modify the XPath context item. I think that the only way to do this is using a / expression. In XPath 2, this means the left side must be a node, but the model attribute sets the context to a node (or the empty sequence) anyway.

So if we had a function, say xxf:model-context-item($model as xs:string) as node()?, we could write an expression like this for the example above:

xxf:model-context-item('2')/(.)

If we have:

<xf:label>
    Hello, <xf:output ref="foo"/>, <xf:output model="m2" ref="bar"/> and <xf:output model="m3" ref="baz"/>!
</xf:label>

We would produce:

concat(
    'Hello, ',
    foo,
    ', ',
    xxf:model-context-item('m2')/(bar),
    ' and ',
    xxf:model-context-item('m3')/(baz),
    '!'
)

So there would be a possibility to support this again. One issue is the namespacing of the function in xxf:. WIth XPath 3 we could use a URIQualifiedName.

This would address the ability to add namespaces on nested xf:output elements (#5308), or to change XBL scopes with xxbl:scope.

avernet commented 2 years ago

In the case the customer is having, we don't really care about the context item, but about the mode changing so instance() resolves its parameter in the new model. So the real use case would be more like:

<xf:label>
    Hello,
     <xf:output model="m1" ref="instance('i1')"/>
    and 
    <xf:output model="m2" ref="instance('i2')"/>!
</xf:label>

If I had to guess, I wouldn't think this can be done with just a function, unless the XPath is passed to the function as a string, as in the following example, which would require proper escaping, maybe multiple times as models can be nested.

xxf:with-model('m1', 'instance(''i1'')')

What would the consequence be of dropping "the requirement to be able to produce a single expression"?