XSLT - apply a template to the result of a call template

Is it possible to apply a template to the result of a call template?

For example, xml and 2 xslt below.

index.xml:

<?xml version="1.0" encoding="UTF-8"?> <root> <book> <title>Ethics</title> </book> <book> <title>Beyond Good and Evil</title> </book> </root> 

index2.xsl

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output indent="yes"/> <xsl:template match="/" name="temp2"> <foo> <xsl:for-each select="//book"> <bar><xsl:value-of select="."/></bar> </xsl:for-each> </foo> </xsl:template> </xsl:stylesheet> 

and index.xsl calls index2.xsl

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output indent="yes"/> <xsl:include href="index2.xsl" /> <!-- apply a template to the <xsl:call-template name="temp2" /> result --> </xsl:stylesheet> 

Is there a way to apply the template to the result <xsl:call-template name="temp2" /> in index.xsl?

Thanks in advance.

+4
source share
1 answer

Is there a way to apply the template to the result <xsl:call-template name="temp2" /> in index.xsl?

Yes, this is called multi-pass processing . The only peculiarity is that in XSLT 1.0 you must apply the implementation-dependent extension function xxx:node-set() to any intermediate result that in the general case will have the infamous RTF (type of result tree) and therefore it is necessary will convert to a regular tree.

Here is a complete example of multiprocessing (I use xsl:apply-templates , not xsl:call-template , but you can freely change this example to use named templates and xsl:call-template instead),

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:template match="/*"> <xsl:variable name="vrtfPass1"> <xsl:apply-templates select="num"/> </xsl:variable> <xsl:apply-templates mode="pass2" select="ext:node-set($vrtfPass1)/*"/> </xsl:template> <xsl:template match="num"> <num><xsl:value-of select="2* ."/></num> </xsl:template> <xsl:template match="num" mode="pass2"> <num><xsl:value-of select=". * ."/></num> </xsl:template> </xsl:stylesheet> 

when this conversion is applied to the following 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>10</num> </nums> 

the desired result (the content of any num elements doubles in the first pass, then the square in the second pass) is created :

 <num>4</num> <num>16</num> <num>36</num> <num>64</num> <num>100</num> <num>144</num> <num>196</num> <num>256</num> <num>324</num> <num>400</num> 

II. In XSLT 2.0

The "RTF type" was canceled, so it’s much easier to specify multi-pass processing , which becomes almost indistinguishable from the functional composition, as shown in the following equivalent conversion:

 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my:my" exclude-result-prefixes="my"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:template match="/*"> <xsl:sequence select="my:squareAll(my:doubleAll(*))"/> </xsl:template> <xsl:function name="my:doubleAll" as="element()*"> <xsl:param name="pElems" as="element()*"/> <xsl:for-each select="$pElems"> <xsl:copy> <xsl:sequence select=". + ."/> </xsl:copy> </xsl:for-each> </xsl:function> <xsl:function name="my:squareAll" as="element()*"> <xsl:param name="pElems" as="element()*"/> <xsl:for-each select="$pElems"> <xsl:copy> <xsl:sequence select=". * ."/> </xsl:copy> </xsl:for-each> </xsl:function> </xsl:stylesheet> 

when this conversion is applied to the same XML document (above), the same correct result is obtained :

 <num>4</num> <num>16</num> <num>36</num> <num>64</num> <num>100</num> <num>144</num> <num>196</num> <num>256</num> <num>324</num> <num>400</num> 
+8
source

Source: https://habr.com/ru/post/1386863/


All Articles