Вы слишком усложняете дела.Как насчет:
<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">
Два советав этом отношении:
- Не делайте для каждого, пока вы можете избежать этого.В 98% случаев вы предпочитаете применять шаблоны (даже если поначалу сложно обойти это).Не поддавайтесь желанию использовать for-each, это раздувает ваш код.
- Не используйте оператор
//
до тех пор, пока вы можете его избежать.Ваш входной XML идеально структурирован, использование //
, как вы делаете, делает эту структуру непригодной для использования, полностью сгладив ее.Вместо этого, попробуйте использовать существующую структуру XML в своих интересах, как я сделал.
РЕДАКТИРОВАТЬ
После комментария от ОП.Решение ниже справляется с любым количеством и видом <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" />