Is there any way to optimize this code.
<xsl:choose>
<xsl:when test="val1 = val2">
<xsl:apply-templates select="node"/>
</xsl:when>
<xsl:otherwise>
<div>
<xsl:apply-templates select="node"/>
</div>
</xsl:otherwise>
</xsl:choose>
I do not like having to write twice the same <xsl:ap开发者_运维知识库ply-templates select="node"/>
.
Update:
The idea is that depending on the result of comparison to do one of two things:
Just print some information (which we obtain after applying the template
<xsl:apply-templates select="node"/>
).Print the same information, but in advance "wrapping" it in the container (
div
for example).
Use:
<xsl:apply-templates select="node">
<xsl:sort select="not(val1 = val2)"/>
</xsl:apply-templates>
Here is a complete example. This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<t>
<xsl:apply-templates select="node">
<xsl:sort select="not(val1 = val2)"/>
</xsl:apply-templates>
</t>
</xsl:template>
<xsl:template match="node[not(val1 = val2)]">
<div>
<node>
<xsl:apply-templates/>
</node>
</div>
</xsl:template>
</xsl:stylesheet>
when applied on this XML document:
<t>
<node>
<val1>1</val1>
<val2>2</val2>
</node>
<node>
<val1>3</val1>
<val2>3</val2>
</node>
</t>
produces the wanted, correct result:
<t>
<node>
<val1>3</val1>
<val2>3</val2>
</node>
<div>
<node>
<val1>1</val1>
<val2>2</val2>
</node>
</div>
</t>
Explanation of the solution:
Whenever an <xsl:apply-templates>
has an <xsl:sort>
child, the nodes that are selected are sorted according the data provided in the <xsl:sort>
child(ren) and the results of applying templates on each selected node appear in the output in that (sort) order -- not in document order.
In the transformation above we have:
<xsl:apply-templates select="node">
<xsl:sort select="not(val1 = val2)"/>
</xsl:apply-templates>
This means that the results of applying templates to the elements named node
for which it is true that val1=val2
will appear before the results of applying templates to the elements named node
for which val1=val2
is not true. This is because false
sorts before true
.
If this explanation is not clear, the reader is directed to read more about <xsl:sort>
.
This is hardy possible for that simple example, but if the amount of the wrapping code and the duplicate code are worth bothering, you have two options:
introduce a chain of templates with different modes:
<!-- instead of choose --> <xsl:apply-template match="." mode="container" /> ... <xsl:template match="container" mode="container"> <xsl:apply-templates select="." mode="dup-group"/> </xsl:template> <xsl:template match="container[val1=val2]" mode="container"> <div> <xsl:apply-templates select="." mode="dup-group"/> </div> </xsl:template> <xsl:template match="container" mode="dup-group"> <xsl:apply-templates select="node"/> <!-- other duplicate code --> ... </xsl:template>
move a part of code into a separate imported stylesheet and override the template rule in the current stylesheet:
<xsl:template match="container[val1=val2]"> <div> <xsl:apply-imports /> </div> </xsl:template>
The xslt you are posting here is not very optimizable. If the code that you don't want to duplicate would be more than two lines, you could optimize by creating a named template and calling that instead. In this example it really doesn't make much sense, but you'll get the idea:
<xsl:when test="val1=val2">
<xsl:call-template name="optimized"/>
</xsl:when>
<xsl:otherwise>
<div>
<xsl:call-template name="optimized"/>
</div>
</xsl:otherwise>
And the template:
<xsl:template name="optimized">
<xsl:apply-templates select="node"/>
</xsl:template>
The called template is in the same context as the calling code, so you can just copy the code you don't want to duplicate to the named template.
精彩评论