The insert action handler

insert allows a node to be inserted into a nodeset, at a certain position. The handler has a set of default behaviours defined which creates for a very powerful and flexible action.

All of the following examples assume this initial instance data:

<instanceData xmlns="">
  <list>
    <y>y1</y>
    <y>y2</y>
    <y>y3</y>
  </list>
  <templates>
    <x>x1</x>
  </templates>
</instanceData>

Duplicating the last node in a nodelist

The simplest form of the handler specifies a nodelist, and duplicates the last item in the list:

<xf:insert nodeset="list/y" />

The result would be:

<list>
  <y>y1</y>
  <y>y2</y>
  <y>y3</y>
  <y>y3</y>
</list>

Specifying the position to duplicate to

It is also possible to indicate a position to copy the last node in the list to. The at attribute indicates which node in the nodeset to place the copied node after:

<xf:insert nodeset="list/y" at="1" />

The result would be:

<list>
  <y>y1</y>
  <y>y3</y>
  <y>y2</y>
  <y>y3</y>
</list>

To place the copied node before the node referred to by @at, use the position attribute with a value of before:

<xf:insert nodeset="list/y" at="1" position="before" />

The result would be:

<list>
  <y>y3</y>
  <y>y1</y>
  <y>y2</y>
  <y>y3</y>
</list>

Note that the default value for @position is after, so the following are equivalent:

<xf:insert nodeset="list/y" at="1" />
<xf:insert nodeset="list/y" at="1" position="after" />

The @at attribute is actually an XPath expression, so it is possible to calculate an insert position at run-time. The expression is evaluated in the context of the first node in the @nodeset, as illustrated by the following example:

<xf:insert nodeset="list/y" at="count(../y) - 1" position="before" />

The result would be:

<list>
  <y>y1</y>
  <y>y3</y>
  <y>y2</y>
  <y>y3</y>
</list>

Copying a node other than the last in the list

It is also possible to copy a node from some other location than the last node in the list, by using the origin attribute. The node could be in the target nodelist:

<xf:insert nodeset="list/y" origin="list/y[1]" />

which would give:

<list>
  <y>y1</y>
  <y>y2</y>
  <y>y3</y>
  <y>y1</y>
</list>

But the node to copy need not be in the nodeset being updated, and could come from some other location, such as a collection of templates:

<xf:insert nodeset="list/y" origin="templates/x" />

The result would be:

<list>
  <y>y1</y>
  <y>y2</y>
  <y>y3</y>
  <x>x1</x>
</list>

Initialising empty nodesets

If the nodeset referred to is empty then the node being copied is created as a child of the insert handler's context node (if you are not clear on the evaluation context then read this):

<xf:group ref="list">
  <xf:repeat nodeset="y">
    <xf:output ref="." />
  </xf:repeat>

  <xf:trigger>
    <xf:label>Add new 'x'</xf:label>
    <xf:action ev:event="DOMActivate">
      <!--
        The evaluation context here is still 'list', from
        the xf:group, above.
      -->
      <xf:insert nodeset="y" origin="../templates/x" />
    </xf:action>
  </xf:trigger>
</xf:group>

In many situations there may be no natural 'context', such as the group in the previous example. In these circumstances we use the context attribute to set a context explicitly:

<xf:insert context="list" nodeset="y" origin="../templates/x" />

Note that the @origin value is also evaluated relative to the evaluation context.