XSLT 1.0 将具有不同值的同一级别的多个相同节点分组
XSLT 1.0 grouping multiple same nodes on same level with different values
我有一个元素列表:
<vehiciles>
<vehicile value="_CAR">CAR</vehicile>
<vehicile value="01">vehicile1</vehicile>
<vehicile value="02">vehicile2</vehicile>
<vehicile value="03">vehicile3</vehicile>
<vehicile value="_TRUCK">TRUCK</vehicile>
<vehicile value="04">vehicile4</vehicile>
<vehicile value="05">vehicile5</vehicile>
<vehicile value="06">vehicile6</vehicile>
</vehiciles>
不幸的是,我无法更改结构,但我必须按车辆指示的类别对其进行分组(在 html select/optgroup 标签中,值以下划线开头。
我想达到的结果:
<select>
<optgroup label="CAR">
<option value="01">vehicile1</option>
<option value="02">vehicile2</option>
<option value="03">vehicile3</option>
</optgroup>
<opgroup label="TRUCK">
<option value="04">vehicile4</option>
<option value="05">vehicile5</option>
<option value="06">vehicile6</option>
</optgroup>
</select>
我试过的是:
<xsl:template match="field" mode="dropdown_list">
<select>
<xsl:choose>
<xsl:when test="vehiciles/vehicile[starts-with(@value, '_')]">
<xsl:for-each select="vehiciles/vehicile[starts-with(@value, '_')]">
<xsl:variable name="lastValue" select="following-sibling::*[starts-with(@value, '_')][@value]" />
<optgroup>
<xsl:attribute name="label">
<xsl:value-of select="text()"/>
</xsl:attribute>
<xsl:for-each select="following-sibling::*[not(preceding::vehicile[1][@value = $lastValue])]">
<option value="{@value}">
<xsl:value-of select="text()"/>
</option>
</xsl:for-each>
</optgroup>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<!-- something here -->
</xsl:otherwise>
</xsl:choose>
</select>
</xsl:template>
它输出第二个循环很好,但第一个包含所有元素。试了好几个小时都没有运气。
试图通过递归来完成,但失败了,就像 Muenchian 分组一样。
有没有办法从某个节点向上查找符合条件的第一个兄弟节点?或者换个方式?
感谢任何帮助。
使用
<xsl:template match="vehiciles">
<select>
<xsl:apply-templates select="vehicile[starts-with(@value, '_')]"/>
</select>
</xsl:template>
<xsl:template match="vehicile[starts-with(@value, '_')]">
<optgroup label="{substring(@value, 2)}">
<xsl:apply-templates select="key('k1', generate-id())"/>
</optgroup>
</xsl:template>
<xsl:key name="k1" match="vehicile[not(starts-with(@value, '_'))]"
use="generate-id(preceding-sibling::vehicile[starts-with(@value, '_')][1])"/>
<xsl:template match="vehicile[not(starts-with(@value, '_'))]">
<xsl:variable name="num">
<xsl:number count="vehicile[not(starts-with(@value, '_'))]"/>
</xsl:variable>
<option value="{format-number($num, '00')}"><xsl:value-of select="."/></option>
</xsl:template>
完整示例请参见 http://xsltransform.net/jyH9rMi。
这样试试:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="vehicile" match="vehicile[not(starts-with(@value, '_'))]" use="generate-id(preceding-sibling::vehicile[starts-with(@value, '_')][1])" />
<xsl:template match="/vehiciles">
<select>
<xsl:for-each select="vehicile[starts-with(@value, '_')]">
<optgroup label="{substring-after(@value, '_')}">
<xsl:for-each select="key('vehicile', generate-id())">
<option value="{@value}">
<xsl:value-of select="."/>
</option>
</xsl:for-each>
</optgroup>
</xsl:for-each>
</select>
</xsl:template>
</xsl:stylesheet>
我有一个元素列表:
<vehiciles>
<vehicile value="_CAR">CAR</vehicile>
<vehicile value="01">vehicile1</vehicile>
<vehicile value="02">vehicile2</vehicile>
<vehicile value="03">vehicile3</vehicile>
<vehicile value="_TRUCK">TRUCK</vehicile>
<vehicile value="04">vehicile4</vehicile>
<vehicile value="05">vehicile5</vehicile>
<vehicile value="06">vehicile6</vehicile>
</vehiciles>
不幸的是,我无法更改结构,但我必须按车辆指示的类别对其进行分组(在 html select/optgroup 标签中,值以下划线开头。
我想达到的结果:
<select>
<optgroup label="CAR">
<option value="01">vehicile1</option>
<option value="02">vehicile2</option>
<option value="03">vehicile3</option>
</optgroup>
<opgroup label="TRUCK">
<option value="04">vehicile4</option>
<option value="05">vehicile5</option>
<option value="06">vehicile6</option>
</optgroup>
</select>
我试过的是:
<xsl:template match="field" mode="dropdown_list">
<select>
<xsl:choose>
<xsl:when test="vehiciles/vehicile[starts-with(@value, '_')]">
<xsl:for-each select="vehiciles/vehicile[starts-with(@value, '_')]">
<xsl:variable name="lastValue" select="following-sibling::*[starts-with(@value, '_')][@value]" />
<optgroup>
<xsl:attribute name="label">
<xsl:value-of select="text()"/>
</xsl:attribute>
<xsl:for-each select="following-sibling::*[not(preceding::vehicile[1][@value = $lastValue])]">
<option value="{@value}">
<xsl:value-of select="text()"/>
</option>
</xsl:for-each>
</optgroup>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<!-- something here -->
</xsl:otherwise>
</xsl:choose>
</select>
</xsl:template>
它输出第二个循环很好,但第一个包含所有元素。试了好几个小时都没有运气。
试图通过递归来完成,但失败了,就像 Muenchian 分组一样。
有没有办法从某个节点向上查找符合条件的第一个兄弟节点?或者换个方式?
感谢任何帮助。
使用
<xsl:template match="vehiciles">
<select>
<xsl:apply-templates select="vehicile[starts-with(@value, '_')]"/>
</select>
</xsl:template>
<xsl:template match="vehicile[starts-with(@value, '_')]">
<optgroup label="{substring(@value, 2)}">
<xsl:apply-templates select="key('k1', generate-id())"/>
</optgroup>
</xsl:template>
<xsl:key name="k1" match="vehicile[not(starts-with(@value, '_'))]"
use="generate-id(preceding-sibling::vehicile[starts-with(@value, '_')][1])"/>
<xsl:template match="vehicile[not(starts-with(@value, '_'))]">
<xsl:variable name="num">
<xsl:number count="vehicile[not(starts-with(@value, '_'))]"/>
</xsl:variable>
<option value="{format-number($num, '00')}"><xsl:value-of select="."/></option>
</xsl:template>
完整示例请参见 http://xsltransform.net/jyH9rMi。
这样试试:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="vehicile" match="vehicile[not(starts-with(@value, '_'))]" use="generate-id(preceding-sibling::vehicile[starts-with(@value, '_')][1])" />
<xsl:template match="/vehiciles">
<select>
<xsl:for-each select="vehicile[starts-with(@value, '_')]">
<optgroup label="{substring-after(@value, '_')}">
<xsl:for-each select="key('vehicile', generate-id())">
<option value="{@value}">
<xsl:value-of select="."/>
</option>
</xsl:for-each>
</optgroup>
</xsl:for-each>
</select>
</xsl:template>
</xsl:stylesheet>