tags:

views:

45

answers:

1

All,

I have an XML file which I transform it using an XSLT document to another XML.

Can I define another set of transformations in the same XSLT file to be applied in the result XML of the first transformation?

Thanks,

MK

+4  A: 

Yes.

I. This XSLT 1.0 transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt"
 >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="vrtfPass1">
  <xsl:apply-templates/>
 </xsl:variable>

 <xsl:template match="node()|@*" name="identity">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="node()|@*" mode="pass2">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*" mode="pass2"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="num/text()">
  <xsl:value-of select="2*."/>
 </xsl:template>

 <xsl:template match="num/text()" mode="pass2">
  <xsl:value-of select="1+."/>
 </xsl:template>

 <xsl:template match="/">
  <xsl:apply-templates select="ext:node-set($vrtfPass1)/*" mode="pass2"/>
 </xsl:template>
</xsl:stylesheet>

when applied on this XML document:

<t>
 <num>1</num>
 <num>2</num>
 <num>3</num>
 <num>4</num>
 <num>5</num>
</t>

produces:

<t>
    <num>3</num>
    <num>5</num>
    <num>7</num>
    <num>9</num>
    <num>11</num>
</t>

Do note:

  1. Two transformations are actually performed, the second is performed on the result of the first.

  2. The result of the first transformation is the content of the variable $vrtfPass1.

  3. In XSLT 1.0 the type of variables that contain dynamically generated (temporary) XML trees (XML document or XML fragment) is RTF (Result-Tree-Fragment). No XPath operations are possible on an RTF -- it needs to be converted to a regular node-set using the extension function xxx:node-set(), which is provided by the vast majority of XSLT 1.0 processor vendors. In this example exslt:node-set() is used, because EXSLT is implemented by many different vendors.

  4. The second transformation is applied on the result of the first: <xsl:apply-templates select="ext:node-set($vrtfPass1)/*" mode="pass2"/> . A separate mode is used in order to cleanly separate the code of the two transformations.

  5. The first transformation multiplies each num/text() by 2. The second transformation increments each num/text(). The result is 2*.+1

II. This XSLT 2.0 transformation:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema" >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="vPass1">
  <xsl:apply-templates mode="pass1"/>
 </xsl:variable>

 <xsl:template match="node()|@*" mode="pass1">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*" mode="pass1"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="node()|@*" mode="pass2">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*" mode="pass2"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="num/text()" mode="pass1">
  <xsl:value-of select="2*xs:integer(.)"/>
 </xsl:template>

 <xsl:template match="num/text()" mode="pass2">
  <xsl:value-of select="1+."/>
 </xsl:template>

 <xsl:template match="/">
  <xsl:apply-templates select="$vPass1"  mode="pass2"/>
 </xsl:template>
</xsl:stylesheet>

when applied on the same XML document, produces the same wanted and correct result.

Do note: In XSLT 2.0/XPath 2.0 the RTF type has been abolished. No xxx:node-set() extension function is needed.

Dimitre Novatchev
@Dimitre: +1 Good answer. This shows why RTF was a bad design choise from WG... Also, Don't we have to show the use of `fn:function-available` when ussing extension functions?
Alejandro
@Alejandro: Maybe using `fn:function-available` would be helpful to determine which one of many `xxx:node-set()` extensions the XSLT processor implements -- but this is usually known.
Dimitre Novatchev
Great. Thanks a lot Dimitre.
koumides