我有这个XML:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="xsl.xsl"?>
<Response>
<Result>
<Date Unix="1263340800">13 Jan 2010 00:00:00</Date>
<Column>
<Name>Small</Name>
<Value>100</Value>
</Column>
</Result>
<Result>
<Date Unix="1263427200">14 Jan 2010 00:00:00</Date>
<Column>
<Name>Small</Name>
<Value>100</Value>
</Column>
</Result>
<Result>
<Date Unix="1263485232">14 Jan 2010 16:07:12</Date>
<Column>
<Name>Normal</Name>
<Value>36.170537</Value>
</Column>
</Result>
<Result>
<Date Unix="1263513600">15 Jan 2010 00:00:00</Date>
<Column>
<Name>Small</Name>
<Value>100</Value>
</Column>
</Result>
</Response>
我想以这种方式呈现数据:
<table>
<tr>
<th>Time</th>
<th>Small</th>
<th>Normal</th>
</tr>
<tr>
<td>13 Jan 2010 00:00:00</td>
<td class="class_Small">100</td>
<td class="class_Normal"></td>
</tr>
<tr>
<td>14 Jan 2010 00:00:00</td>
<td class="class_Small">100</td>
<td class="class_Normal"></td>
</tr>
<tr>
<td>14 Jan 2010 16:07:12</td>
<td class="class_Small"></td>
<td class="class_Normal">39.301737</td>
</tr>
<tr>
<td>15 Jan 2010 00:00:00</td>
<td class="class_Small">100</td>
<td class="class_Normal"></td>
</tr>
</table>
这是我目前的XSL:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="Friendlies" match="Name" use="."/>
<xsl:template match="/">
<table>
<tr>
<th>Time</th>
<!-- Output the Column Names -->
<xsl:for-each select="//Column">
<!-- Only ouput the Name if it is the first occurence of this value -->
<xsl:if test="generate-id(Name) = generate-id(key('Friendlies',Name)[1])">
<th>
<xsl:value-of select="Name"/>
</th>
</xsl:if>
</xsl:for-each>
</tr>
<!-- Loop through all Results -->
<xsl:for-each select="//Result">
<xsl:variable name="UnixTimestamp" select="Date/@Unix"/>
<tr>
<td>
<xsl:value-of select="Date"/>
</td>
<xsl:for-each select="//Column">
<xsl:if test="generate-id(Name) = generate-id(key('Friendlies',Name)[1])">
<xsl:element name="td">
<xsl:attribute name="class">class_<xsl:value-of select="Name"/></xsl:attribute>
<xsl:value-of select="[Date/@Unix=$UnixTimestamp]/Value"/>
</xsl:element>
</xsl:if>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
HTML结构出来了。唯一的问题是值不会出现在单元格中。我意识到<xsl:value-of select="[Date/@Unix=$UnixTimestamp]/Value"/>
不是正确的引用,因为Date元素实际上与Column元素处于同一级别,而不在其中。我想不出应该怎么做。
另外,我不确定我是否正在使用最好的方法,因为看起来很少有输出会发生很多循环。随着XML变得更大(更多结果,更多列),我想知道是否会对性能产生影响。
原谅我,我是XSL的新手。
提前致谢。
有关XML的一些信息:
<Column>
节点中的任意数量的<Result>
个节点<Date>
节点中只有一个<Result>
节点<Name>
节点中只有一个<Column>
节点<Name>
节点的值可以是任何值,而不仅仅是“小”或“正常”答案 0 :(得分:4)
你的事情过于复杂。怎么样:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output encoding="utf-8" indent="yes" />
<xsl:template match="Response">
<table>
<tr>
<th>Time</th>
<th>Small</th>
<th>Normal</th>
</tr>
<xsl:apply-templates select="Result" />
</table>
</xsl:template>
<xsl:template match="Result">
<tr>
<td><xsl:value-of select="Date" /></td>
<td><xsl:value-of select="Column[Name = 'Small']/Value" /></td>
<td><xsl:value-of select="Column[Name = 'Normal']/Value" /></td>
</tr>
</xsl:template>
</xsl:stylesheet>
输出完全符合您的要求:
<table>
<tr>
<th>Time</th>
<th>Small</th>
<th>Normal</th>
</tr>
<tr>
<td>13 Jan 2010 00:00:00</td>
<td>100</td>
<td></td>
</tr>
<tr>
<td>14 Jan 2010 00:00:00</td>
<td>100</td>
<td></td>
</tr>
<tr>
<td>14 Jan 2010 16:07:12</td>
<td></td>
<td>36.170537</td>
</tr>
<tr>
<td>15 Jan 2010 00:00:00</td>
<td>100</td>
<td></td>
</tr>
</table>
你的XSLT非常复杂,主要是因为:
<xsl:for-each select="//Column">
这方面的两个提示:
//
运算符,请不要使用它。您的输入XML使用//
完美结构化,就像您通过完全展平它而使此结构无法使用一样。相反,尝试使用现有的XML结构,就像我已经完成的那样。修改强>
跟进OP的评论。下面的解决方案可以处理任何数量和种类的<Name>
节点。它使用for-each,但作为抽象迭代的一种手段,而不是作为处理子节点的手段。
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output encoding="utf-8" indent="yes" />
<xsl:key name="kName" match="Name" use="." />
<xsl:variable name="vName" select="
//Name[generate-id() = generate-id(key('kName', .)[1])]
" />
<xsl:template match="Response">
<table>
<tr>
<th>Time</th>
<xsl:for-each select="$vName">
<th><xsl:value-of select="." /></th>
</xsl:for-each>
</tr>
<xsl:apply-templates select="Result" />
</table>
</xsl:template>
<xsl:template match="Result">
<xsl:variable name="self" select="." />
<tr>
<td><xsl:value-of select="Date" /></td>
<xsl:for-each select="$vName">
<td><xsl:value-of select="$self/Column[Name = current()]/Value" /></td>
</xsl:for-each>
</tr>
</xsl:template>
</xsl:stylesheet>
您可以使用<xsl:sort>
修改生成列的顺序。
为了获得大输入文档的最佳性能,另一个调整可以加速这个表达式:
<xsl:value-of select="$self/Column[Name = current()]/Value" />
使用这个附加键:
<xsl:key name="kColumn" match="Column" use="concat(Name,'|',generate-id(..))" />
你可以把它重写为:
<xsl:value-of select="key('kColumn', concat(.,'|',generate-id($self)))/Value" />