我正在改进我继承的一些样式表,并将它们从使用<xsl:for-each>
转换为<xsl:apply-templates>
。我将要使用的XML文件的一个非常简化的版本是:
<Root>
<Row ID="123" Region="AMS">
<First>Graham</First>
<Last>Smith</Last>
<Sales>12345.85</Sales>
<Team>Team A</Team>
</Row>
<Row id="321">
<First>John</First>
<Last>Brown</Last>
<Sales>18765.85</Sales>
<Team>Team C</Team>
</Row>
<Row id="456" Region="EMEA">
<First>Anne</First>
<Last>Jones</Last>
<Sales>34567.85</Sales>
<Team>Team B</Team>
</Row>
</Root>
我的新样式表是:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html" indent="yes"/>
<xsl:variable name="RowCount" select="count(/*/*)"/>
<xsl:template match="/@* | node()">
<style>
body * {font-family:Arial;font-size:11pt}
table {border-collapse:collapse}
td {border-bottom:1px solid #D8D8D8;padding:7px}
tr.row1 {background:#F9F9F9;}
td.tdHeader {border-bottom:2px solid #DDD;font-weight:700}
</style>
<table>
<thead>
<tr>
<xsl:apply-templates select="*[1]/@*" mode="headerAttributes" />
<xsl:apply-templates select="*[1]/*" mode="headerFields"/>
</tr>
</thead>
<tbody>
<xsl:apply-templates select="*"/>
</tbody>
</table>
</xsl:template>
<xsl:template match="/*/*/@*" mode="headerAttributes">
<td class="tdHeader">
<xsl:value-of select="name()" />
</td>
</xsl:template>
<xsl:template match="/*/*/*" mode="headerFields">
<td class="tdHeader">
<xsl:value-of select="name()" />
</td>
</xsl:template>
<xsl:template match="/*/*">
<tr class="row{position() mod 2}">
<xsl:apply-templates select="@*" mode="attributes"/>
<xsl:apply-templates select="*" mode="fields"/>
</tr>
</xsl:template>
<xsl:template match="/*/*/@*" mode="attributes">
<td>
<xsl:value-of select="." />
</td>
</xsl:template>
<xsl:template match="/*/*/*" mode="fields">
<td>
<xsl:value-of select="." />
</td>
</xsl:template>
</xsl:stylesheet>
但是,由于XML中的第二个节点缺少<Region>
属性,结果上的单元格排列错误,现在在Region列中有名字,在first name列中有姓氏,等等。如果Row节点上缺少子节点,也会发生这种情况。例如,没有team元素
在调用apply-template之前,以及在最后两个模板中,我尝试测试一个缺失的节点,但是没有效果。
任何想法?我遗漏了什么?我只是刚刚开始使用应用模板,但其他编写样式表的方法我很好。
暂时,这适用于您的输入:
<xsl:template match="Row">
<tr class="row{position() mod 2}">
<td><xsl:apply-templates select="@ID|@id" mode="attr2"/></td>
<td><xsl:apply-templates select="@Region" mode="attr2"/></td>
<xsl:apply-templates select="*" mode="fields"/>
</tr>
</xsl:template>
<xsl:template match="@ID|@id|@Region" mode="attr2">
<b><xsl:value-of select="." /></b>
</xsl:template>
——您可以删除mode="attributes"
的所有内容。
即使没有id|ID
或Region
属性,也强制包含<td>..</td>
对。
Saxon 8.8报告错误:
从document-node()节点开始的属性轴永远不会选择任何东西
因为你的
<xsl:template match="/@* | node()">
将其更改为<xsl:template match="node()">
,或者最好更改为<xsl:template match="Root">
将解决此问题。正如我在评论中所说,尽量少使用*
。对Root
和Row
的引用可以更改为精确匹配