Temporary Trees

Temporary Trees and xsl:sequence

A variable with content instead of select holds a temporary tree, a new document you can query like any input (XSLT 1.0's "result tree fragment" could not be), which makes multi-pass transformations easy. xsl:sequence returns items as they are, including existing nodes, while xsl:copy-of creates new ones, so functions should return with xsl:sequence:

trees.xsl: a temporary tree of order lines and a function returning nodesXML
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:bn="urn:booknest:fn"
    exclude-result-prefixes="#all" expand-text="yes">
  <xsl:output method="text"/>
  <xsl:variable name="lines">
    <xsl:for-each select="doc('../s2-15/orders.xml')//order">
      <xsl:variable name="price" select="$catalog//book[identifier = current()/@sku]//price"/>
      <line sku="{@sku}" amount="{xs:integer(@qty) * xs:decimal($price)}"/>
    </xsl:for-each>
  </xsl:variable>
  <xsl:variable name="catalog" select="/"/>
  <xsl:function name="bn:top" as="element(book)">
    <xsl:sequence select="$catalog//book[.//price = max($catalog//price)]"/>
  </xsl:function>
  <xsl:template match="/">
    <xsl:text>{count($lines/*)} lines: {sum($lines/line/xs:decimal(@amount))}&#10;</xsl:text>
    <xsl:variable name="copy" as="element()"><xsl:copy-of select="bn:top()"/></xsl:variable>
    <xsl:text>Same node: {bn:top() is //book[2]}, copy: {$copy is //book[2]}&#10;</xsl:text>
  </xsl:template>
</xsl:stylesheet>
Output
8 lines: 289.62
Same node: true, copy: false

$catalog keeps the catalog in reach while the context is an order in another file. Temporary-tree nodes are untyped, so cast @amount; and with an untyped @qty, @qty * $price becomes xs:double (a first draft summed to 289.61999999999995).