我正在尝试将一些XML输出转换为评级表(水文相关),其中包括跨越顶部的百分之一值和下降的十分之一值。我遇到的问题是我似乎无法通过在ht属性上使用子字符串来排序唯一值。
以下是XML输出的示例:
<env:Envelope>
<env:Header/>
<env:Body>
<RatingTableUpdate>
<Gauge xmlns="" type="STORAGE" id="123">
<Input input="0">
<Conv ht="19.76" cap="5040" />
<Conv ht="19.77" cap="5045" />
<Conv ht="19.78" cap="5051" />
<Conv ht="19.79" cap="5057" />
<Conv ht="19.80" cap="5063" />
<Conv ht="19.81" cap="5069" />
<Conv ht="19.82" cap="5074" />
<Conv ht="19.83" cap="5080" />
<Conv ht="19.84" cap="5086" />
<Conv ht="19.85" cap="5092" />
<Conv ht="19.86" cap="5098" />
<Conv ht="19.87" cap="5104" />
<Conv ht="19.88" cap="5109" />
<Conv ht="19.89" cap="5115" />
<Conv ht="19.90" cap="5121" />
<Conv ht="19.91" cap="5127" />
<Conv ht="19.92" cap="5133" />
<Conv ht="19.93" cap="5138" />
</Input>
</Gauge>
</RatingTableUpdate>
</env:Body>
</env:Envelope>
输出应如下所示:
GH 0.00 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09
19.7 5040 5045 5051 5057
19.8 5063 5069 5074 5080 5086 5092 5098 5104 5109 5115
19.9 5121 5127 5133 5138
我能够在正确的列中获取cap属性,但是无法获得GH列(删除了百分之一值的ht属性),每行只显示一次。我得到这样的东西:
GH 0.00 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09
19.7 5040
5045
5051
5057
19.8 5063
5069
5074
5080
5086
5092
5098
5104
5109
5115
19.9 5121
5127
5133
5138
这是我的xsl部分,用于格式化此部分。 xsl:choose似乎适用于列。我已经尝试过Muenchian方法但是无法正确使用它(很难让它使用子串键)。
这是最好的方法,还是有另一种方法让每一行只显示给定子字符串一次(19.76,19.77,19.78,19.79值为19.7)?评级通常从像示例那样的非零值开始,所以我不能只使用百分之0的值来启动一个组而使用9来结束一个组。
<xsl:for-each select="env:Envelope/env:Body/RatingTableUpdate/Gauge">
<table width="100%">
<tr class="site">
<td width="150px">Site ID: <u><xsl:value-of select="@id" /></u></td>
<td>Site Name: <u><xsl:value-of select="@idname" /></u></td>
<td>Type: <u><xsl:value-of select="@type" /></u></td>
</tr>
</table>
<table width="100%">
<tr class="tbldata">
<th rowspan="1" class="tbldataheader">GH</th>
<th rowspan="1" class="tbldataheader">0.00</th>
<th rowspan="1" class="tbldataheader">0.01</th>
<th rowspan="1" class="tbldataheader">0.02</th>
<th rowspan="1" class="tbldataheader">0.03</th>
<th rowspan="1" class="tbldataheader">0.04</th>
<th rowspan="1" class="tbldataheader">0.05</th>
<th rowspan="1" class="tbldataheader">0.06</th>
<th rowspan="1" class="tbldataheader">0.07</th>
<th rowspan="1" class="tbldataheader">0.08</th>
<th rowspan="1" class="tbldataheader">0.09</th>
</tr>
<xsl:for-each select="./Input/Conv">
<tr class="tbldata">
<xsl:choose>
<xsl:when test="substring(@ht,string-length(@ht),1) = 0">
<td class="ifrtext"><xsl:value-of select="substring(@ht,1,string-length(@ht)-1)" /></td>
</xsl:when>
<xsl:otherwise>
<td class="ifrtext"></td>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="substring(@ht,string-length(@ht),1) = 0">
<td class="ifrtext"><xsl:value-of select="@cap" /></td>
</xsl:when>
<xsl:otherwise>
<td class="ifrtext"></td>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="substring(@ht,string-length(@ht),1) = 1">
<td class="ifrtext"><xsl:value-of select="@cap" /></td>
</xsl:when>
<xsl:otherwise>
<td class="ifrtext"></td>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="substring(@ht,string-length(@ht),1) = 2">
<td class="ifrtext"><xsl:value-of select="@cap" /></td>
</xsl:when>
<xsl:otherwise>
<td class="ifrtext"></td>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="substring(@ht,string-length(@ht),1) = 3">
<td class="ifrtext"><xsl:value-of select="@cap" /></td>
</xsl:when>
<xsl:otherwise>
<td class="ifrtext"></td>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="substring(@ht,string-length(@ht),1) = 4">
<td class="ifrtext"><xsl:value-of select="@cap" /></td>
</xsl:when>
<xsl:otherwise>
<td class="ifrtext"></td>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="substring(@ht,string-length(@ht),1) = 5">
<td class="ifrtext"><xsl:value-of select="@cap" /></td>
</xsl:when>
<xsl:otherwise>
<td class="ifrtext"></td>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="substring(@ht,string-length(@ht),1) = 6">
<td class="ifrtext"><xsl:value-of select="@cap" /></td>
</xsl:when>
<xsl:otherwise>
<td class="ifrtext"></td>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="substring(@ht,string-length(@ht),1) = 7">
<td class="ifrtext"><xsl:value-of select="@cap" /></td>
</xsl:when>
<xsl:otherwise>
<td class="ifrtext"></td>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="substring(@ht,string-length(@ht),1) = 8">
<td class="ifrtext"><xsl:value-of select="@cap" /></td>
</xsl:when>
<xsl:otherwise>
<td class="ifrtext"></td>
</xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="substring(@ht,string-length(@ht),1) = 9">
<td class="ifrtext"><xsl:value-of select="@cap" /></td>
</xsl:when>
<xsl:otherwise>
<td class="ifrtext"></td>
</xsl:otherwise>
</xsl:choose>
</tr>
</xsl:for-each>
</table>
</xsl:for-each>
谢谢, 马特
答案 0 :(得分:2)
此转化:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kValByTenths" match="Conv"
use="substring(@ht, 1, 4)"/>
<xsl:key name="kCapFromHt" match="@cap"
use="../@ht"/>
<xsl:template match="Input">
<table>
<xsl:for-each select=
"Conv[generate-id()
=
generate-id(key('kValByTenths',substring(@ht, 1, 4))[1])
]">
<xsl:variable name="vKey" select="substring(@ht, 1, 4)"/>
<tr>
<td><xsl:value-of select="$vKey"/></td>
<xsl:for-each select=
"(//node() | //namespace::*)[not(position() > 10)]">
<xsl:variable name="vPos" select="position()"/>
<td>
<xsl:value-of select="key('kCapFromHt', concat($vKey,$vPos -1))"/>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档(更正为格式良好的XML文档):
<env:Envelope xmlns:env="some:env">
<env:Header/>
<env:Body>
<RatingTableUpdate>
<Gauge xmlns="" type="STORAGE" id="123">
<Input input="0">
<Conv ht="19.76" cap="5040" />
<Conv ht="19.77" cap="5045" />
<Conv ht="19.78" cap="5051" />
<Conv ht="19.79" cap="5057" />
<Conv ht="19.80" cap="5063" />
<Conv ht="19.81" cap="5069" />
<Conv ht="19.82" cap="5074" />
<Conv ht="19.83" cap="5080" />
<Conv ht="19.84" cap="5086" />
<Conv ht="19.85" cap="5092" />
<Conv ht="19.86" cap="5098" />
<Conv ht="19.87" cap="5104" />
<Conv ht="19.88" cap="5109" />
<Conv ht="19.89" cap="5115" />
<Conv ht="19.90" cap="5121" />
<Conv ht="19.91" cap="5127" />
<Conv ht="19.92" cap="5133" />
<Conv ht="19.93" cap="5138" />
</Input>
</Gauge>
</RatingTableUpdate>
</env:Body>
</env:Envelope>
生成想要的(没有装饰),正确的结果:
<table>
<tr>
<td>19.7</td>
<td/>
<td/>
<td/>
<td/>
<td/>
<td/>
<td>5040</td>
<td>5045</td>
<td>5051</td>
<td>5057</td>
</tr>
<tr>
<td>19.8</td>
<td>5063</td>
<td>5069</td>
<td>5074</td>
<td>5080</td>
<td>5086</td>
<td>5092</td>
<td>5098</td>
<td>5104</td>
<td>5109</td>
<td>5115</td>
</tr>
<tr>
<td>19.9</td>
<td>5121</td>
<td>5127</td>
<td>5133</td>
<td>5138</td>
<td/>
<td/>
<td/>
<td/>
<td/>
<td/>
</tr>
</table>
<强>解释强>:
正确使用 Muenchian grouping method ,其中Conv
元素由其ht
属性的字符串值的前4个字符编入索引。
正确使用 Piez method 进行非递归迭代N次。
<强>更新强>:
OP已报告由于MSXML3中的错误,使用IE 8时无法获得正确的结果。
这是一个经过修改的解决方案,也适用于MSXML3 / IE 8:
<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:key name="kValByTenths" match="Conv"
use="substring(@ht, 1, 4)"/>
<xsl:variable name="vConvs" select="//Conv"/>
<xsl:template match="Input">
<table>
<xsl:for-each select=
"Conv[generate-id()
=
generate-id(key('kValByTenths',substring(@ht, 1, 4))[1])
]">
<xsl:variable name="vKey" select="substring(@ht, 1, 4)"/>
<tr>
<td><xsl:value-of select="$vKey"/></td>
<xsl:for-each select=
"(//node() | //namespace::*)[not(position() > 10)]">
<xsl:variable name="vPos" select="position()"/>
<td>
<xsl:value-of select=
"$vConvs[substring-after(@ht, $vKey) = $vPos]/@cap"/>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>