The evaluation context

XForms uses XPath expressions in many places, and it is important as an author to understand how these expressions are evaluated. Perhaps the most important concept is that of the evaluation context.

When an XPath expression is evaluated, the processor needs to know both the model and the instance against which to evaluate the expression. Since all expressions are evaluated in some context then it should always be possible to work out the meaning of even short expressions such as "/".

To illustrate the context rules, we'll begin with the simplest situation, when the form being processed has only one model and one instance:

  <xf:model id="mdl">
    <xf:instance id="inst">
      <a xmlns="">
        <b />
      </a>
    </xf:instance>
  </xf:model>

Explicit references

We'll look first at all the ways we could bind to element b. The first approach is to make everything--both the model and the instance--explicit:

  <xf:input model="mdl" ref="instance('inst')/b">
    <xf:label>B:</xf:label>
  </xf:input>

In a small form we would be unlikely to use this explicit syntax since there are so many shortcuts available to us. But this syntax does have the advantage that it will always refer to element b, regardless of where in our form it is placed. For example, if we wanted to show the value of b in the hint of some other control, we would need to use this explicit syntax if the other control was in another model:

  <xf:input model="mdl2" ref="instance('inst2')/d">
    <xf:label>D:</xf:label>
    <xf:hint>
      Please enter a
      '<xf:output model="mdl" ref="instance('inst')/b" />'
    </xf:hint>
  </xf:input>

The 'First Instance' rule

Perhaps the simplest abbreviation we can make on our earlier mark-up is to make use of the 'First Instance' rule, which says that if no instance is specified, the first instance in the specified model should be used. Our previous example can be altered to remove the use of instance():

  <xf:input model="mdl" ref="b">
    <xf:label>B:</xf:label>
  </xf:input>

We can safely rely on this rule in our example so far, since we only have one instance, but once our forms get to a reasonable size it is probably worth specifying the instance explicitly. That way, if form controls are moved around or a new instance is added to a model, the form will continue to work correctly.

To illustrate the kinds of problems that can arise, in the following example a new instance has been added, but since it has been placed first in the model, the previous reference to b is no longer bound correctly since it relied on the 'first instance' rule, and 'inst3' is now the first instance:

  <xf:model id="mdl">
    <xf:instance id="inst3">
      <c xmlns="">
        <d />
      </c>
    </xf:instance>

    <xf:instance id="inst">
      <a xmlns="">
        <b />
      </a>
    </xf:instance>
  </xf:model>

  <xf:input model="mdl" ref="b">
    <xf:label>B:</xf:label>
  </xf:input>

We can fix this by referring to the instance explicitly, and if we had made our initial references explicit then we would not have had a problem in the first place.

The 'First Model' rule

In the same way that if there is no instance specified the first one is implied, so too if no model is specified then the first model will be used. With this in mind, we can further abbreviate our expression:

  <xf:model id="mdl">
    <xf:instance id="inst">
      <a xmlns="">
        <b />
      </a>
    </xf:instance>
  </xf:model>

  <xf:input ref="/a/b">
    <xf:label>B:</xf:label>
  </xf:input>

or:

  <xf:input ref="b">
    <xf:label>B:</xf:label>
  </xf:input>

This last control only works because the evaluation context is actually the root element of the instance document (a) and not the document itself. In other words, the expression "*" (which means return all children of the context node) would return b and not a.

Using group to set context for a number of controls

When overriding the 'first model' or 'first instance' rules, as discussed above, it is not always necessary to place the model or instance that you want directly onto a control; if there is more than one control then it is certainly more efficient to use a group:

  <xf:model id="mdl">
    <xf:instance id="inst3">
      <c xmlns="">
        <d />
        <e />
      </c>
    </xf:instance>

    <xf:instance id="inst">
      <a xmlns="">
        <b />
      </a>
    </xf:instance>
  </xf:model>

  <xf:model id="mdl2">
    <xf:instance id="inst2">
      <c xmlns="">
        <d />
      </c>
    </xf:instance>
  </xf:model>

  <xf:group model="mdl">
    <xf:input ref="d">
      <xf:label>D:</xf:label>
    </xf:input>
    <xf:input ref="e">
      <xf:label>E:</xf:label>
    </xf:input>
  </xf:group>

Rather than having @model on each of the two controls, things are more succinct by setting a new evaluation context for all the controls via a group.

Conclusion

A number of strategies are available in XForms to abbreviate an XPath expression. Which one we use for a particular form will depend on how our form will evolve.