The xf:setnode action is an experimental extension of XForms, helpful for updating an instance document with the output of an XSLT transformation (see the transform() function) or with the output of a mixed-content editor (see the discussion of using TinyMCE as an XForms control).

The action is indicated using the xf:setnode element. It has three crucial attributes:

  • The ref attribute is a single-node binding attribute which indicates the target node.
  • The inner attribute specifies the node(s) which should replace the children of the target node; its value is the serialized XML form of the nodes.
  • The outer attribute specifies the node which should replace the target node; its value is the serialized XML form of the replacement node.

The inner and outer attributes are mutually exclusive; one or the other must be specified, but not both. As is usual when representing serialized XML within an attribute value, the left angle brackets and ampersands in the serialized form must be escaped.

The value of the inner or outer attribute is parsed as XML to produce DOM nodes, and the resulting nodes replace either the children of the target node, or the target node itself.

Example

edit

The following example shows a trigger which replaces an instance named input with a new document.

  <xf:trigger>
    <xf:label>Generate diagram</xf:label>
    <xf:action ev:event="DOMActivate">
      <xf:setnode ref="instance('input')" 
                  outer="&lt;doc&gt;
  &lt;title&gt;My document&lt;/title&gt;
  &lt;chapter&gt;
      &lt;p&gt;Hello, world!&lt;/p&gt;
  &lt;/chapter&gt;
&lt;/doc&gt;"/>
    </xf:action>
  </xf:trigger>

Using setnode with transform()

edit

A perhaps more common usage of setnode is to update an instance with the result of running an XSLT stylesheet or a mixed-content editor, both of which return strings with the serialized-XML form of their result.

Suppose we have an input instance which the user can modify through the form, and an XSLT stylesheet (make-svg.xsl) which can process the input instance and create an SVG diagram representing some information from the instance. To allow the user to generate a fresh diagram, we could supply a trigger specified as follows:

  <xf:trigger>
    <xf:label>Generate diagram</xf:label>
    <xf:action ev:event="DOMActivate">
      <xf:setnode ref="instance('svg')" 
                   outer="transform(instance('input'),'make-svg.xsl')"/>
      <xf:toggle case="picture"/>
    </xf:action>
  </xf:trigger>

This assumes that we have an instance named svg, where the output of the transformation should go. It also assumes that there is a switch statement somewhere with a case named picture, which displays the generated SVG.

Achieving similar effects in standard XForms 1.1

edit

In standard XForms 1.1, one way to achieve similar effects is to submit the string (the serialized XML) to a server which reflects it back unchanged, with the MIME type application/xml (or similar), and specify that the submission updates the instance in question.

The example given above would be rewritten as:

  <xf:trigger>
    <xf:label>Generate diagram</xf:label>
    <xf:action ev:event="DOMActivate">
      <xf:setvalue ref="instance('svg')" 
                   value="transform(instance('input'),'make-svg.xsl')"/>
      <xf:send submission="parse-as-xml"/>
      <xf:toggle case="picture"/>
    </xf:action>
  </xf:trigger>

The parse-as-xml submission submits the string value of the svg instance to the server, which reflects it back as XML (so the browser parses it and updates the instance normally):

  <xf:submission id="parse-as-xml"
                 ref="instance('svg')/text()"
                 method="post"
                 resource="../lib/reflect-as-xml.sh"
                 replace="instance"
                 instance="svg"
                 />

The CGI script on the server does nothing but return the submitted data, labeled as XML:

#!/bin/sh
echo "Content-Type: application/xml"
echo
cat

Achieving similar effects in standard XForms 2.0

edit

To achieve similar effects in XForms 2.0, one can use the xf:insert action, using the XForms 2.0 parse() function in the value of the origin attribute.

[Example needed.]