tags:

views:

655

answers:

1

Greetings,

I'm looking for a method to do in-line result (output) document selecting in XSLT. I know of the method where one creates an xsl:result-document node to have one transformation apply to multiple documents. Usually this method uses several passes, such as:

<xsl:template match="/">
    <xsl:apply-templates select="*"/>
    <xsl:result-document href="test.xml">
        <xsl:apply-templates select="*"/>
    </xsl:result-document>
</xsl:template>

I'm looking for a way to do this inline so I can build two output documents in a single pass. The reason is I have a temporary tree that is built as the transformation is run that I want to output to a file.

<xsl:variable name="treeBase">
    <Base/>
</xsl:variable>

<xsl:template match="/">
    <xsl:apply-templates select="*"/>
</xsl:template>

<xsl:template match="these_elements">
    <xsl:param name="temp" select="$treeBase"/>


</xsl:template>

<xsl:template match="not_these_elements">
    <xsl:param name="temp" select="$treeBase"/>

    <xsl:apply-templates select="@*|node()">
       <xsl:with-param name="temp">
           <Base>
              <xsl:copy-of select="$temp/Base/*"/>
              <Item>
                  <xsl:value-of select="ThisItem"/>
              </Item>
           </Base>
        </xsl:with-param>
</xsl:template>

Why would you want to do this? In my XSLT I'm building a temporary tree through recursive parameter calls. I want to output the temporary tree as it is being built to a separate document but still use the temporary tree built for flow of control. With the current method I'd have to run through a complex transformation twice.

Is there a way to do this in XSLT or is it single-pass, single-document only?

Thanks in advance.

+1  A: 

Here is a working example how to do this:

This transformation:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"&gt;
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <!--                                               -->    
    <xsl:template match="/*">
      <xsl:variable name="vTop" select="."/>
  <!--                                               -->    
        <xsl:for-each-group select="num" group-by="xs:integer(.) mod 2">
          <xsl:result-document href="file:///C:/Temp/file{position()}.xml">
            <xsl:element name="{name($vTop)}">
              <xsl:copy-of select="current-group()"/>
            </xsl:element>
          </xsl:result-document>
        </xsl:for-each-group>
    </xsl:template>
</xsl:stylesheet>

when applied on this XML document

<nums>
  <num>01</num>
  <num>02</num>
  <num>03</num>
  <num>04</num>
  <num>05</num>
  <num>06</num>
  <num>07</num>
  <num>08</num>
  <num>09</num>
  <num>010</num>
</nums>

produces the wanted two files: file1.xml and file2.xml, which contain, correspondingly, the "num" elements with odd and with even values.

Do note that there are no "multiplr passes" and the code is "inline", as required.

Dimitre Novatchev
great solution Dimitre!
Jweede