Description edit

The xf:include element includes external files in a form at compile time, during the evaluation of the xsltforms.xsl stylesheet. It is thus similar in functionality to general entities in XML, or to the XInclude xi:include element.

It can be used to reduce duplication of code at multiple points in a form, to share code between forms, or just to move a complex part of a subform into a separate document to make the logic of the main form clearer and easier to follow.

Syntax edit

The xf:include element is empty. It carries just one attribute: src.

The value of the src attribute is a URI reference (absolute or relative) pointing to an XML document to be included in the form.

Examples edit

Repeated code within a form edit

Consider an XForm which accepts query data from a user, submits a query to a back end search engine, and displays the results to the user. To avoid overloading the user's browser and/or the network, we wish to send only a page's worth of results to the user at any one time, and allow the user to page through the results, so-and-so many results at a time.

The general outline of such a form might be something like this; we assume an instance named query to hold the query string and the starting position within the results, and an instance named results to hold the results.

<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:xf="http://www.w3.org/2002/xforms"
      xmlns:ev="http://www.w3.org/2001/xml-events">
<head>
    ...
</head>
<body>
    <h2>Query tool</h2>

    ... controls for query string, submission ...

    <xf:group ref="instance('results')/self::result[.//hits]">

        ... code for Back and Forward buttons ... 

        <xf:repeat nodeset="self::test//hits/hit">
            ... display one hit ...
        </xf:repeat>

        ... code for Back and Forward buttons ...
      
    </xf:group>
</body>
</html>

To reduce the need for scrolling up and down in the results page, we wish to have buttons for moving forward and back in the results both at the top of the results list and at the bottom. The code will be the same for both: first a Back button, which displays only if the current starting position is greater than 1:

<xf:group ref=".[instance('query')/startpos > 1]">
    <xf:trigger>
        <xf:label>Back</xf:label>
        <xf:action ev:event="DOMActivate">
            <xf:setvalue ref="instance('query')/startpos" 
                value="instance('query')/startpos - instance('query')/pagesize "/>
            <xf:send submission="send-query"/>
        </xf:action>
    </xf:trigger>
</xf:group>

Then a message indicating location in the results (e.g. "11 to 20 of 34", or "No results"):

<xf:group ref=".[.//hits/@n > 0][.//hit]">
    <p>Results <xf:output ref=".//hit[1]/@n"/>
        to <xf:output value=".//hit[last()]/@n"/>
        of <xf:output value="instance('results')//hits/@n"/>
    </p>
</xf:group>
<xf:group ref=".[.//hits/@n = 0]">
    <p>No results.</p>
</xf:group>

And finally a Forward button, which displays only if we are not currently displaying the last hit:

<xf:group ref=".[(instance('query')/startpos + count(.//hit)) 
               &lt;= (self::test/results/hits/@n)]">  
    <xf:trigger>
        <xf:label>Forward</xf:label>
        <xf:action ev:event="DOMActivate">
            <xf:setvalue ref="instance('query')/startpos" 
                value="instance('query')/startpos + instance('query')/pagesize"/>
            <xf:send submission="send-query"/>
        </xf:action>
    </xf:trigger>
</xf:group>

Note that the forward and back buttons, and the current-location message, have no IDs that need to be unique; there is no problem including their text twice in the form. To make that happen, we must

  1. Make an XML document containing the Back button, the location message, and the Forward button. We wrap these three elements in an XHTML div element to give the XML a single root element, and call the result file "FBButtons.xhtml".
  2. In the appropriate locations in the main form, use the xf:include element with the appropriate src value. If "FBButtons.xhtml" was placed in the same directory as the main form, we'll use <xf:include src="FBButtons.xhtml"/>.

Known problems and issues edit

  • The xf:include element works as specified in the main XForm, and recursively in documents loaded via xf:include. In subforms, which are loaded later, it works in some browsers but not in others (including Webkit-based browsers). Cause of this discrepancy is the unwillingness of some browsers to evaluate the XSLT document() function in XSLT stylesheets invoked from Javascript, which is motivated by security concerns of some description.
  • Browsers will enforce the same-origin policy, which means the absolute URI pointing to the XML document to be include will need to be on the same host as the form itself. [Tests and empirical confirmation of this claim would be desirable.]

For further information edit