如何用XSLT的group-adjacent创建两个不同规则的表单分组?
问题描述
我有一份需要转换为表单的HTML文件,内容如下:
<p class="textfield">Text field</p> <p class="checkboxfield">Check Box field</p> <p class="drop_downlistfield">Drop-down list field 1</p> <p class="drop_downlistfield">Drop-down list field 2</p> <p class="drop_downlistfield">Drop-down list field 3</p> <p class="radiobuttonfield">Radio Button field 1</p> <p class="radiobuttonfield">Radio Button field 2</p> <p class="radiobuttonfield">Radio Button field 3</p> <p class="submitbuttonfield">Submit button</p>
转换要求:
- 将class为
drop_downlistfield的段落合并为一个下拉列表组:
<select> <option value="Drop-down list field 1">Drop-down list field 1</option> <option value="Drop-down list field 2">Drop-down list field 2</option> <option value="Drop-down list field 3">Drop-down list field 3</option> </select>
- 将class为
radiobuttonfield的段落按统一的name属性分组为单选按钮组:
<input type="radio" id="ID_1929_6" name="radiogroup"></input> <label for="ID_1929_6">Radio Button field 1</label> <input type="radio" id="ID_1929_7" name="radiogroup"></input> <label for="ID_1929_7">Radio Button field 2</label> <input type="radio" id="ID_1929_8" name="radiogroup"></input> <label for="ID_1929_8">Radio Button field 3</label>
我可以单独对其中一类创建分组:
<xsl:for-each-group select="table|p|ul|ol" group-adjacent="(@class='radiobuttonfield')">
但无法同时创建两个独立分组——如果用or条件,会把两类合并成一组:
<xsl:for-each-group select="table|p|ul|ol" group-adjacent="(@class='radiobuttonfield') or (@class='drop_downlistfield')">
请问如何将输入片段拆分为两个独立的分组?
解决方案
要实现两类字段的独立分组,核心是基于具体的class值而非布尔判断来分组,以下是两种可行方法:
方法1:使用group-by按class值分组
直接以元素的@class作为分组依据,自动将同class的元素归为一组(无论是否相邻):
<xsl:for-each-group select="p" group-by="@class"> <xsl:choose> <!-- 处理下拉列表组 --> <xsl:when test="current-grouping-key() = 'drop_downlistfield'"> <select> <xsl:for-each select="current-group()"> <option value="{.}"><xsl:value-of select="."/></option> </xsl:for-each> </select> </xsl:when> <!-- 处理单选按钮组 --> <xsl:when test="current-grouping-key() = 'radiobuttonfield'"> <xsl:for-each select="current-group()"> <xsl:variable name="id" select="concat('ID_1929_', position() + 5)"/> <input type="radio" id="{$id}" name="radiogroup"/> <label for="{$id}"><xsl:value-of select="."/></label> </xsl:for-each> </xsl:when> <!-- 处理其他类型字段 --> <xsl:otherwise> <!-- 可根据需求扩展转换逻辑,比如转为对应表单控件 --> <xsl:copy-of select="current-group()"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group>
方法2:使用group-adjacent返回具体class值
如果仅需要合并连续的同类型元素,让group-adjacent返回实际class值而非布尔结果:
<xsl:for-each-group select="p" group-adjacent="@class"> <xsl:choose> <xsl:when test="current-grouping-key() = 'drop_downlistfield'"> <select> <xsl:for-each select="current-group()"> <option value="{.}"><xsl:value-of select="."/></option> </xsl:for-each> </select> </xsl:when> <xsl:when test="current-grouping-key() = 'radiobuttonfield'"> <xsl:for-each select="current-group()"> <xsl:variable name="id" select="concat('ID_1929_', position() + 5)"/> <input type="radio" id="{$id}" name="radiogroup"/> <label for="{$id}"><xsl:value-of select="."/></label> </xsl:for-each> </xsl:when> <xsl:otherwise> <xsl:copy-of select="current-group()"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group>
关键说明
- 两种方法的核心差异在于分组范围:
group-by聚合所有同class元素,group-adjacent仅聚合连续的同class元素,可根据实际场景选择。 - 其他类型字段(如
textfield、checkboxfield)可在otherwise分支中添加专属转换逻辑,比如转为<input type="text">或<input type="checkbox">。
内容的提问来源于stack exchange,提问作者Hobbes
相关产品推荐
相关产品推荐

