You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XSLT 1.0嵌套分组问题:基于Muenchian方法实现数据分组

解决XSLT 1.0按NR分组并按ITEM映射列的表格转换问题

需求与现有问题

需要将给定的XML数据通过XSLT 1.0转换为指定结构的HTML表格:按NR字段分组,每个分组对应一行;每行需按固定顺序展示ITEM-A、ITEM-C、ITEM-B的相关属性(ITEM值、颜色、材质),缺失则留空。现有代码已实现NR分组,但无法正确映射不同ITEM到对应列。

原始XML数据

<?xml version="1.0" encoding="UTF-8"?>
<RESULTSET>
   <RES>
      <NR>1</NR>
      <TYPE >XXX </TYPE>
      <ITEM>A</ITEM>
      <COLOUR>blue</COLOUR>
      <MATERIAL>wood</MATERIAL>
      <COUNTER>1</COUNTER>
    </RES>
   <RES>
      <NR>2</NR>
      <TYPE >YYY </TYPE>
      <ITEM>A</ITEM>
      <COLOUR>red</COLOUR>
      <MATERIAL>plastic</MATERIAL>
      <COUNTER>1</COUNTER>
   </RES>
<RES>
      <NR>2</NR>
      <TYPE >YYY </TYPE>
      <ITEM>C</ITEM>
      <COLOUR>pink</COLOUR>
      <MATERIAL>wood</MATERIAL>
      <COUNTER>3</COUNTER>
   </RES>
   <RES>
      <NR>3</NR>
      <TYPE >ZZZ </TYPE>
      <ITEM>C</ITEM>
      <COLOUR>yellow</COLOUR>
      <MATERIAL>metal</MATERIAL>
      <COUNTER>3</COUNTER>
    </RES>
   <RES>
      <NR>1</NR>
      <TYPE >XXX</TYPE>
      <ITEM>B</ITEM>
      <COLOUR>yellow</COLOUR>
      <MATERIAL>metal</MATERIAL>
      <COUNTER>2</COUNTER>
    </RES>
</RESULTSET>

期望输出HTML表格

<div class="s-table-container">
<table class="s-table">
<thead>
<tr>
<th>NR</th>
<th>TYPE</th>
<th>ITEM-A</th>
<th>COL-A</th>
<th>MAT-A</th>
<th>ITEM-C</th>
<th>COL-C</th>
<th>MAT-C</th>
<th>ITEM-B</th>
<th>COL-B</th>
<th>MAT-B</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>XXX</td>
<td>A</td>
<td>blue</td>
<td>wood</td>
<td></td>
<td></td>
<td></td>
<td>B</td>
<td>yellow</td>
<td>metal</td>
</tr>
<tr>
<td>2</td>
<td>YYY</td>
<td>A</td>
<td>red</td>
<td>plastic</td>
<td>C</td>
<td>pink</td>
<td>wood</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>3</td>
<td>ZZZ</td>
<td></td>
<td></td>
<td></td>
<td>C</td>
<td>yellow</td>
<td>metal</td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>

现有XSLT代码

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="res-by-nr" match="RES" use="NR" />
<xsl:template match="RESULTSET">
<th>NR</th>
<th>TYPE</th>
<th>ITEM-A</th>
<th>COL-A</th>
<th>MAT-A</th>
<th>ITEM-B</th>
<th>COL-B</th>
<th>MAT-B</th>
<th>ITEM-C</th>
<th>COL-C</th>
<th>MAT-C</th>
<br></br>
  <xsl:for-each select="RES[count(. | key('res-by-nr', NR)[1]) = 1]">
    <xsl:sort select="NR" />
    <tr>
     <td><xsl:value-of select="NR" /></td>
     <td><xsl:value-of select="TYPE" /></td>
             <xsl:for-each select="key('res-by-nr', NR)">
               <xsl:sort select="Counter" />
             <xsl:choose>
               <xsl:when test = "ITEM='A'">
                     <td><xsl:value-of select="ITEM"/></td>
                     <td><xsl:value-of select="COLOUR"/></td>
                     <td><xsl:value-of select="MATERIAL"/></td>
               </xsl:when>
               <xsl:otherwise>
                     <td>Test</td>
                     <td>Test</td>
                     <td>Test</td>
                </xsl:otherwise>
                </xsl:choose> 
     </xsl:for-each>
  </tr>
  </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

修正后的XSLT代码

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- Muenchian分组:按NR分组 -->
    <xsl:key name="res-by-nr" match="RES" use="NR"/>

    <xsl:template match="/RESULTSET">
        <div class="s-table-container">
            <table class="s-table">
                <thead>
                    <tr>
                        <th>NR</th>
                        <th>TYPE</th>
                        <th>ITEM-A</th>
                        <th>COL-A</th>
                        <th>MAT-A</th>
                        <th>ITEM-C</th>
                        <th>COL-C</th>
                        <th>MAT-C</th>
                        <th>ITEM-B</th>
                        <th>COL-B</th>
                        <th>MAT-B</th>
                    </tr>
                </thead>
                <tbody>
                    <!-- 遍历每个唯一的NR分组 -->
                    <xsl:for-each select="RES[count(. | key('res-by-nr', NR)[1]) = 1]">
                        <xsl:sort select="NR" data-type="number"/>
                        <tr>
                            <!-- 输出NR和去空格后的TYPE -->
                            <td><xsl:value-of select="NR"/></td>
                            <td><xsl:value-of select="normalize-space(TYPE)"/></td>

                            <!-- 处理ITEM-A的列 -->
                            <xsl:variable name="itemA" select="key('res-by-nr', NR)[ITEM='A']"/>
                            <xsl:choose>
                                <xsl:when test="$itemA">
                                    <td><xsl:value-of select="$itemA/ITEM"/></td>
                                    <td><xsl:value-of select="$itemA/COLOUR"/></td>
                                    <td><xsl:value-of select="$itemA/MATERIAL"/></td>
                                </xsl:when>
                                <xsl:otherwise>
                                    <td></td>
                                    <td></td>
                                    <td></td>
                                </xsl:otherwise>
                            </xsl:choose>

                            <!-- 处理ITEM-C的列 -->
                            <xsl:variable name="itemC" select="key('res-by-nr', NR)[ITEM='C']"/>
                            <xsl:choose>
                                <xsl:when test="$itemC">
                                    <td><xsl:value-of select="$itemC/ITEM"/></td>
                                    <td><xsl:value-of select="$itemC/COLOUR"/></td>
                                    <td><xsl:value-of select="$itemC/MATERIAL"/></td>
                                </xsl:when>
                                <xsl:otherwise>
                                    <td></td>
                                    <td></td>
                                    <td></td>
                                </xsl:otherwise>
                            </xsl:choose>

                            <!-- 处理ITEM-B的列 -->
                            <xsl:variable name="itemB" select="key('res-by-nr', NR)[ITEM='B']"/>
                            <xsl:choose>
                                <xsl:when test="$itemB">
                                    <td><xsl:value-of select="$itemB/ITEM"/></td>
                                    <td><xsl:value-of select="$itemB/COLOUR"/></td>
                                    <td><xsl:value-of select="$itemB/MATERIAL"/></td>
                                </xsl:when>
                                <xsl:otherwise>
                                    <td></td>
                                    <td></td>
                                    <td></td>
                                </xsl:otherwise>
                            </xsl:choose>
                        </tr>
                    </xsl:for-each>
                </tbody>
            </table>
        </div>
    </xsl:template>
</xsl:stylesheet>

关键改进点

  1. 完善表格结构:补充了thead、tbody以及外层的div容器,完全匹配期望输出的HTML结构。
  2. 固定列映射:不再遍历分组内的所有RES节点,而是直接按期望的列顺序(A→C→B)查找对应ITEM的节点,确保列位置正确。
  3. 处理空值:对每个ITEM类型,判断是否存在对应节点,不存在则输出空<td>。
  4. 数据格式化:用normalize-space(TYPE)去除TYPE字段的多余空格,和期望输出一致。
  5. 排序优化:给NR排序加上data-type="number",确保数字排序正确。

内容的提问来源于stack exchange,提问作者Leonfauko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 02:51:06