Main Template for Advanced xsl:for-each Example
Since this XSLT stylesheet produces tables with essentially the
same structure as the simple <xsl:for-each>
example, the main template is similar to the one used in the simple
example.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0" xmlns:oms="http://xml.spss.com/spss/oms">
<!--enclose everything in a template, starting at the root node-->
<xsl:template match="/">
<HTML>
<HEAD>
<TITLE>Modified Frequency Tables</TITLE>
</HEAD>
<BODY>
<xsl:for-each select="//oms:pivotTable[@subType='Frequencies']">
<xsl:for-each select="oms:dimension[@axis='row']">
<h3>
<xsl:call-template name="showVarInfo"/>
</h3>
</xsl:for-each>
<!--create the HTML table-->
<table border="1">
<tbody align="char" char="." charoff="1">
<tr> <th>Category</th><th>Count</th><th>Percent</th>
</tr>
<xsl:for-each select="descendant::oms:dimension[@axis='column']">
<xsl:if test="oms:category[3]">
<tr>
<td>
<xsl:choose>
<xsl:when test="parent::*/@varName">
<xsl:call-template name="showValueInfo"/>
</xsl:when>
<xsl:when test="not(parent::*/@varName)">
<b><xsl:value-of select="parent::*/@text"/></b>
</xsl:when>
</xsl:choose>
</td>
<td>
<xsl:apply-templates select="oms:category[1]/oms:cell/@number"/>
</td>
<td>
<xsl:apply-templates select="oms:category[3]/oms:cell/@number"/>
</td>
</tr>
</xsl:if>
</xsl:for-each>
</tbody>
</table>
<xsl:if test="descendant::*/oms:note">
<p><xsl:value-of select="descendant::*/oms:note/@text"/></p>
</xsl:if>
</xsl:for-each>
</BODY>
</HTML>
</xsl:template>
This template is very similar to the one for the simple example. The main differences are:
-
<xsl:call-template name="showVarInfo"/>
calls another template to determine what to show for the table title instead of simply using thetext
attribute of the row dimension (oms:dimension[@axis='row']
). See the topic Controlling Variable and Value Label Display for more information. -
<xsl:if test="oms:category[3]">
selects only the data in the 'Valid' section of the table instead of<xsl:if test="ancestor::oms:group[@text='Valid']">
. The positional argument used in this example doesn't rely on localized text. It relies on the fact that the basic structure of a frequency table is always the same and the fact that OXML does not include elements for empty cells. Since the 'Missing' section of a frequency table contains values only in the first two columns, there are nooms:category[3]
column elements in the 'Missing' section, so the test condition is not met for the 'Missing' rows. See the topic XPath Expressions in Multiple Language Environments for more information. -
<xsl:when test="parent::*/@varName">
selects the nontotal rows instead of<xsl:when test="not((parent::*)[@text='Total'])">
. Column elements in the nontotal rows in a frequency table contain avarName
attribute that identifies the variable, whereas column elements in total rows do not. So this selects nontotal rows without relying on localized text. -
<xsl:call-template name="showValueInfo"/>
calls another template to determine what to show for the row labels instead of<xsl:value-of select="parent::*/@text"/>
. See the topic Controlling Variable and Value Label Display for more information. -
<xsl:apply-templates select="oms:category[1]/oms:cell/@number"/>
selects the value in the 'Frequency' column instead of<xsl:value-of select="oms:category[@text='Frequency']/oms:cell/@text"/>
. A positional argument is used instead of localized text (the 'Frequency' column is always the first column in a frequency table), and a template is applied to determine how to display the value in the cell. Percentage values are handled the same way, usingoms:category[3]
to select the values from the 'Valid Percent' column. See the topic Controlling Decimal Display for more information.