XSLT Muenchian 分组嵌套行和列

XSLT Muenchian grouping nested rows and columns

我正在使用 XSLT 1.0。我的 XML 文件中有 <RowBreak><ColumnBreak> 元素。 RowBreak 将按行对我的数据进行分组,而 ColumnBreak 将转换为列。只要 ColumnBreak 或 RowBreak 没有匹配项,显示就应该继续向下显示。

这是我的 XML:

<?xml version="1.0" encoding="utf-8" ?>
<Tree>
  <Item>
    <Label>Item 1</Label>
  </Item>
  <Item>
    <Label>Item 2</Label>
  </Item>
  <ColumnBreak />
  <Item>
    <Label>Item 3</Label>
  </Item>
  <Item>
    <Label>Item 4</Label>
  </Item>
  <Item>
    <Label>Item 5</Label>
  </Item>
  <RowBreak />
  <Item>
    <Label>Item 6</Label>
  </Item>
  <Item>
    <Label>Item 7</Label>
  </Item>
  <ColumnBreak />
  <Item>
    <Label>Item 8</Label>
  </Item>
  <RowBreak />
  <Item>
    <Label>Item 9</Label>
  </Item>
  <Item>
    <Label>Item 10</Label>
  </Item>
</Tree>

预期的输出是这样的:

Item 1  Item 3
Item 2  Item 4
        Item 5

Item 6  Item 8
Item 7

Item 9
Item 10

编辑: 这是我更新的 XSLT。我仍然不知道如何进行嵌套分组。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="html" indent="yes"/>
  <xsl:key name="rowGroups" match="Tree/*[not(self::RowBreak)]" use="count(preceding-sibling::RowBreak)" />

  <xsl:template match="Tree">
    <xsl:variable name="rowGroupings" select="*[not(self::RowBreak)][generate-id() = generate-id(key('rowGroups', count(preceding-sibling::RowBreak))[1])]" />
    <xsl:variable name="position" select="position()" />
    <table>
      <xsl:for-each select="$rowGroupings">
        <xsl:variable name="rowId" select="generate-id()"/>
        <xsl:variable name="colGroupings" select="$rowGroupings[not(self::ColumnBreak)][generate-id()=$rowId][1]" />
        <tr>
          <td>
            <xsl:for-each select="$colGroupings">
              <xsl:sort select="$colGroupings[preceding-sibling::ColumnBreak]" order="descending" />
              <xsl:if test="position() = 1">
                <xsl:variable name="maxRows" select="$colGroupings[preceding-sibling::ColumnBreak]" />
                <xsl:call-template name="ColumnGroupTemplate">
                  <xsl:with-param name="maxRows" select="$maxRows" />
                  <xsl:with-param name="colGroupings" select="$colGroupings" />
                </xsl:call-template>
              </xsl:if>
            </xsl:for-each>
          </td>
        </tr>
      </xsl:for-each>
    </table>
  </xsl:template>

  <xsl:template name="ColumnGroupTemplate">
    <xsl:param name="maxRows" />
    <xsl:param name="colGroupings" />
    <xsl:for-each select="$maxRows">
      <xsl:variable name="position" select="position()" />
      <tr>
        <xsl:for-each select="$colGroupings">
          <xsl:variable name="group" select="$colGroupings[preceding-sibling::ColumnBreak]" />
          <td>
            <xsl:value-of select="normalize-space($colGroupings[position() = $position])" />
          </td>
        </xsl:for-each>
      </tr>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

如何使用 Muenchian 分组获得预期的输出?谢谢!

如果您将此样式表应用于您的输入 XML

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:strip-space elements="*"/>
    <xsl:output method="html" version="5.0" />


    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Tree">
        <table>
            <!-- process the first row -->
            <xsl:call-template name="process_first_group">
                <xsl:with-param name="group" select="*[not(preceding-sibling::RowBreak) 
                    and not(self::RowBreak)]"/>
            </xsl:call-template>
            <xsl:apply-templates select="RowBreak"/>
        </table>
    </xsl:template>

    <!-- succeeding rows that start with RowBreak -->
    <xsl:template match="RowBreak">
        <xsl:variable name="row_ID" select="generate-id()"/>
        <xsl:variable name="prec_Col" select="count(preceding-sibling::ColumnBreak)"/>
        <xsl:call-template name="process_other_group">
            <xsl:with-param name="group" select="following-sibling::*[not(self::RowBreak)]
                [preceding-sibling::RowBreak[1]
                [generate-id()=$row_ID]
                ]"/>
            <xsl:with-param name="row_ID" select="$row_ID"/>
            <xsl:with-param name="prec_Col" select="$prec_Col"/>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="process_first_group">
        <xsl:param name="group"/>
        <xsl:for-each select="$group[self::Item[not(preceding-sibling::ColumnBreak)]]">
            <xsl:variable name="pos" select="position()"/>
            <tr>
                <td>
                    <xsl:value-of select="."/>
                </td>
                <xsl:for-each select="following-sibling::ColumnBreak">
                    <xsl:variable name="col_ID" select="generate-id()"/>
                    <xsl:apply-templates select="$group[self::Item
                        [preceding-sibling::ColumnBreak[1]
                        [generate-id()=$col_ID]
                        ]
                        [position()=$pos]
                        ]"/>
                </xsl:for-each>
            </tr>
        </xsl:for-each>
    </xsl:template>

    <xsl:template name="process_other_group">
        <xsl:param name="group"/>
        <xsl:param name="row_ID"/>
        <xsl:param name="prec_Col"/>
        <xsl:for-each select="$group[self::Item[count(preceding-sibling::ColumnBreak)=$prec_Col]]">
            <xsl:variable name="pos" select="position()"/>
            <tr>
                <td>
                    <xsl:value-of select="."/>
                </td>
                <xsl:for-each select="$group[self::ColumnBreak[preceding-sibling::RowBreak[generate-id()=$row_ID]]]">
                    <xsl:variable name="col_ID" select="generate-id()"/>
                    <xsl:apply-templates select="following-sibling::Item[preceding-sibling::ColumnBreak[1][generate-id()=$col_ID] and preceding-sibling::RowBreak[1][generate-id()=$row_ID]][position()=$pos]"/>
                </xsl:for-each>
            </tr>
        </xsl:for-each>
    </xsl:template>

    <xsl:template match="Item">
        <td><xsl:apply-templates/></td>
    </xsl:template>

    <xsl:template match="Label">
        <xsl:apply-templates/>
    </xsl:template>

</xsl:stylesheet>

你会得到

<table>
   <tr>
      <td>Item 1</td>
      <td>Item 3</td>
   </tr>
   <tr>
      <td>Item 2</td>
   </tr>
   <tr>
      <td>Item 4</td>
      <td>Item 6</td>
      <td>Item 8</td>
   </tr>
   <tr>
      <td>Item 5</td>
      <td>Item 7</td>
   </tr>
   <tr>
      <td>Item 9</td>
   </tr>
   <tr>
      <td>Item 10</td>
   </tr>
</table>

查看实际效果 https://xsltfiddle.liberty-development.net/3NzcBuj/1