平面结构的XSLT转换为多层嵌套结构

时间:2012-11-09 22:13:42

标签: xslt-1.0

我是XML / XLST处理的新手,我正在一个必须使用版本1处理的环境中工作。我有一个从Excel电子表格导出的XML文件。该文件如下所示:

<?xml version="1.0" encoding="utf-8"?>
<TmData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Version="10"
Date="2012-11-07T10:11:09.017242-05:00" Format="1" Author="System" Description="Import"
Culture="en-US">
<DocumentElement>
    <Risks>
        <FOLDER/>
        <FOLDER1>Management</FOLDER1>
        <FOLDER2>Human Resources</FOLDER2>
        <RISK_x0020_FOLDER>Knowledge and People</RISK_x0020_FOLDER>
        <TITLE>Insufficient investment in training</TITLE>
        <CODE>code001</CODE>
        <RISKCATEGORY1>Securtiy</RISKCATEGORY1>
        <RISKCATEGORY2>Indirect Assertion</RISKCATEGORY2>
        <RISKNUMBERICVALUE1>32.5</RISKNUMBERICVALUE1>
        <RISKYESNO1>1</RISKYESNO1>
        <RISKYESNO2>0</RISKYESNO2>
        <_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
            [Risks]</_SheetName>
        <_RowNumber>6</_RowNumber>
    </Risks>
    <Risks>
        <FOLDER/>
        <FOLDER1>Management</FOLDER1>
        <FOLDER2>Human Resources</FOLDER2>
        <RISK_x0020_FOLDER>Knowledge and People</RISK_x0020_FOLDER>
        <TITLE>Over-reliance on one or a few key employees</TITLE>
        <CODE>code002</CODE>
        <RISKCATEGORY3>Securtity</RISKCATEGORY3>
        <RISKYESNO1>0</RISKYESNO1>
        <RISKYESNO2>1</RISKYESNO2>
        <WEIGHT>323.5</WEIGHT>
        <_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
            [Risks]</_SheetName>
        <_RowNumber>7</_RowNumber>
    </Risks>
    <Risks>
        <FOLDER/>
        <FOLDER1>Management</FOLDER1>
        <FOLDER2>Human Resources</FOLDER2>
        <RISK_x0020_FOLDER>Knowledge and People</RISK_x0020_FOLDER>
        <TITLE>Inability to recruit / retain staff</TITLE>
        <CODE>code003</CODE>
        <_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
            [Risks]</_SheetName>
        <_RowNumber>8</_RowNumber>
    </Risks>
    <Risks>
        <FOLDER/>
        <FOLDER1>Management</FOLDER1>
        <FOLDER2>Human Resources</FOLDER2>
        <RISK_x0020_FOLDER>Knowledge and People</RISK_x0020_FOLDER>
        <TITLE>Unexpected / unbudgeted cost increases</TITLE>
        <CODE>code004</CODE>
        <_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
            [Risks]</_SheetName>
        <_RowNumber>9</_RowNumber>
    </Risks>
    <Risks>
        <FOLDER/>
        <FOLDER1>Management</FOLDER1>
        <FOLDER2>Financial</FOLDER2>
        <RISK_x0020_FOLDER>Financial Div</RISK_x0020_FOLDER>
        <TITLE>Failure to achieve margins</TITLE>
        <CODE>code005</CODE>
        <RISKNUMBERICVALUE1>232.5</RISKNUMBERICVALUE1>
        <RISKYESNO1>1</RISKYESNO1>
        <RISKYESNO2>0</RISKYESNO2>
        <_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
            [Risks]</_SheetName>
        <_RowNumber>12</_RowNumber>
    </Risks>
    <Risks>
        <FOLDER/>
        <FOLDER1>Management</FOLDER1>
        <FOLDER2>Financial</FOLDER2>
        <RISK_x0020_FOLDER>Financial Div</RISK_x0020_FOLDER>
        <TITLE>Adverse impact of exchange rate fluctuations</TITLE>
        <CODE>code006</CODE>
        <RISKYESNO1>1</RISKYESNO1>
        <_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
            [Risks]</_SheetName>
        <_RowNumber>13</_RowNumber>
    </Risks>
    <Risks>
        <FOLDER>ACME Manufacturing</FOLDER>
        <FOLDER1/>
        <FOLDER2/>
        <RISK_x0020_FOLDER>Strategic / Vision</RISK_x0020_FOLDER>
        <TITLE>Strategy is not implemented</TITLE>
        <CODE>code008</CODE>
        <RISKNUMBERICVALUE1>0</RISKNUMBERICVALUE1>
        <RISKYESNO2>0</RISKYESNO2>
        <WEIGHT>10000000000.58</WEIGHT>
        <_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
            [Risks]</_SheetName>
        <_RowNumber>16</_RowNumber>
    </Risks>
    <Risks>
        <FOLDER>ACME Manufacturing</FOLDER>
        <FOLDER1/>
        <FOLDER2/>
        <RISK_x0020_FOLDER>Strategic / Vision</RISK_x0020_FOLDER>
        <TITLE>Failure to have and execute R&amp;D plans</TITLE>
        <CODE>code009</CODE>
        <RISKYESNO1>1</RISKYESNO1>
        <RISKYESNO2>0</RISKYESNO2>
        <_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
            [Risks]</_SheetName>
        <_RowNumber>17</_RowNumber>
    </Risks>
    <Risks>
        <FOLDER>ACME Manufacturing</FOLDER>
        <FOLDER1/>
        <FOLDER2/>
        <RISK_x0020_FOLDER>Strategic / Vision</RISK_x0020_FOLDER>
        <TITLE>Risk management practices do not exist</TITLE>
        <CODE>code010</CODE>
        <RISKYESNO1>1</RISKYESNO1>
        <RISKYESNO2>0</RISKYESNO2>
        <_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
            [Risks]</_SheetName>
        <_RowNumber>18</_RowNumber>
    </Risks>
    <Risks>
        <FOLDER>ACME Manufacturing</FOLDER>
        <FOLDER1>Environment</FOLDER1>
        <FOLDER2/>
        <RISK_x0020_FOLDER>Environment Div</RISK_x0020_FOLDER>
        <TITLE>Community involvement objectives are not clearly articulated</TITLE>
        <CODE>code011</CODE>
        <RISKYESNO1>0</RISKYESNO1>
        <RISKYESNO2>0</RISKYESNO2>
        <_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
            [Risks]</_SheetName>
        <_RowNumber>21</_RowNumber>
    </Risks>
    <Risks>
        <FOLDER>ACME Manufacturing</FOLDER>
        <FOLDER1>Environment</FOLDER1>
        <FOLDER2/>
        <RISK_x0020_FOLDER>Environment Div</RISK_x0020_FOLDER>
        <TITLE>Time off for community involvement is no adequately controlled</TITLE>
        <CODE>code012</CODE>
        <RISKYESNO1>0</RISKYESNO1>
        <RISKYESNO2>0</RISKYESNO2>
        <_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
            [Risks]</_SheetName>
        <_RowNumber>22</_RowNumber>
    </Risks>
    <Risks>
        <FOLDER>ACME Manufacturing</FOLDER>
        <FOLDER1>Market</FOLDER1>
        <FOLDER2/>
        <RISK_x0020_FOLDER>Market Div</RISK_x0020_FOLDER>
        <TITLE>Brand / reputation damage by company environmental failure</TITLE>
        <CODE>Ad.358</CODE>
        <RISKYESNO1>0</RISKYESNO1>
        <RISKYESNO2>1</RISKYESNO2>
        <_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
            [Risks]</_SheetName>
        <_RowNumber>25</_RowNumber>
    </Risks>
    <Risks>
        <FOLDER>ACME Manufacturing</FOLDER>
        <FOLDER1>Market</FOLDER1>
        <FOLDER2/>
        <RISK_x0020_FOLDER>Market Div</RISK_x0020_FOLDER>
        <TITLE>Supply of raw materials affected by environmental failure</TITLE>
        <CODE>CK.324</CODE>
        <RISKYESNO1>0</RISKYESNO1>
        <RISKYESNO2>1</RISKYESNO2>
        <_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
            [Risks]</_SheetName>
        <_RowNumber>26</_RowNumber>
    </Risks>
    <Risks>
        <FOLDER>ACME Manufacturing</FOLDER>
        <FOLDER1>Market</FOLDER1>
        <FOLDER2/>
        <RISK_x0020_FOLDER>Market Div</RISK_x0020_FOLDER>
        <TITLE>Loss of business through unattractive product / service offerings</TITLE>
        <CODE>AABB01</CODE>
        <RISKYESNO1>0</RISKYESNO1>
        <RISKYESNO2>1</RISKYESNO2>
        <_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
            [Risks]</_SheetName>
        <_RowNumber>27</_RowNumber>
    </Risks>
    <Risks>
        <FOLDER>ACME Manufacturing</FOLDER>
        <FOLDER1>Market</FOLDER1>
        <FOLDER2/>
        <RISK_x0020_FOLDER>Market Div</RISK_x0020_FOLDER>
        <TITLE>Natural disaster</TITLE>
        <CODE>CCDD03</CODE>
        <RISKYESNO1>0</RISKYESNO1>
        <RISKYESNO2>1</RISKYESNO2>
        <_SheetName>C:\Users\Hugh.Manning\AppData\Local\Temp\CDEA67E1F7034E89B86DD770700A7B19\82F56919D18640DA9EC54FE569B6A3F8.xls
            [Risks]</_SheetName>
        <_RowNumber>28</_RowNumber>
    </Risks>
</DocumentElement>
</TmData>

我需要输出看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<TmData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
Version="10"
Date="2012-10-31T09:35:28.9068981-04:00" Format="1" Author="System" Description="Import"
Culture="en-US"><FOLDERS>
<FOLDER>
  <Title/>
  <FOLDERS>
    <FOLDER>
      <Title>Management</Title>
      <FOLDERS>
        <FOLDER>
          <Title>Human Resources</Title>
          <FOLDERS>
            <FOLDER>
              <Title>Knowledge and People</Title>
              <Risk>
                <TITLE>Insufficient investment in training</TITLE>
                <CODE>code001</CODE>
                <RISKCATEGORY1>Security</RISKCATEGORY1>
                <RISKCATEGORY2>Indirect Assertion</RISKCATEGORY2>
                <RISKNUMBERICVALUE1>32.5</RISKNUMBERICVALUE1>
                <RISKYESNO1>1</RISKYESNO1>
                <RISKYESNO2>0</RISKYESNO2>
              </Risk>
              <Risk>
                <TITLE>Over-reliance on one or a few key employees</TITLE>
                <CODE>code002</CODE>
                <RISKCATEGORY3>Security</RISKCATEGORY3>
                <RISKYESNO1>0</RISKYESNO1>
                <RISKYESNO2>1</RISKYESNO2>
              </Risk>
              <Risk>
                <TITLE>Inability to recruit / retain staff</TITLE>
                <CODE>code003</CODE>
              </Risk>
              <Risk>
                <TITLE>
                  Unexpected / unbudgeted cost
                  increases
                </TITLE>
                <CODE>code004</CODE>
              </Risk>
            </FOLDER>
          </FOLDERS>
        </FOLDER>
        <FOLDER>
          <Title>Financial</Title>
          <FOLDERS>
            <FOLDER>
              <Title>Financial Div</Title>
              <Risk>
                <TITLE>Failure to achieve margins</TITLE>
                <CODE>code005</CODE>
                <RISKNUMBERICVALUE1>232.5</RISKNUMBERICVALUE1>
                <RISKYESNO1>1</RISKYESNO1>
                <RISKYESNO2>0</RISKYESNO2>
              </Risk>
              <Risk>
                <TITLE>
                  Adverse impact of exchange rate
                  fluctuations
                </TITLE>
                <CODE>code006</CODE>
                <RISKYESNO1>1</RISKYESNO1>
              </Risk>
            </FOLDER>
          </FOLDERS>
        </FOLDER>
      </FOLDERS>
    </FOLDER>
  </FOLDERS>
</FOLDER>
<FOLDER>
  <Title>ACME Manufacturing</Title>
  <FOLDERS>
    <FOLDER>
      <Title/>
      <FOLDERS>
        <FOLDER>
          <Title/>
          <FOLDERS>
            <FOLDER>
              <Title>Strategic / Vision</Title>
              <Risk>
                <TITLE>Strategy is not implemented</TITLE>
                <CODE>code008</CODE>
                <RISKNUMBERICVALUE1>0</RISKNUMBERICVALUE1>
                <RISKYESNO2>0</RISKYESNO2>
                <WEIGHT>10000000000.58</WEIGHT>
              </Risk>
              <Risk>
                <TITLE>Failure to have and execute R&amp;D plans</TITLE>
                <CODE>code009</CODE>
                <RISKYESNO1>1</RISKYESNO1>
                <RISKYESNO2>0</RISKYESNO2>
              </Risk>
              <Risk>
                <TITLE>Risk management practices do not exist</TITLE>
                <CODE>code010</CODE>
                <RISKYESNO1>1</RISKYESNO1>
                <RISKYESNO2>0</RISKYESNO2>
              </Risk>
            </FOLDER>
          </FOLDERS>
        </FOLDER>
      </FOLDERS>
    </FOLDER>
    <FOLDER>
      <Title>Environment</Title>
      <FOLDERS>
        <FOLDER>
          <Title/>
          <FOLDERS>
            <FOLDER>
              <Title>Environment Div</Title>
              <Risk>
                <TITLE>
                  Community involvement objectives are not
                  clearly articulated
                </TITLE>
                <CODE>code011</CODE>
                <RISKYESNO1>0</RISKYESNO1>
                <RISKYESNO2>0</RISKYESNO2>
              </Risk>
              <Risk>
                <TITLE>
                  Time off for community involvement is no
                  adequately controlled
                </TITLE>
                <CODE>code012</CODE>
                <RISKYESNO1>0</RISKYESNO1>
                <RISKYESNO2>0</RISKYESNO2>
              </Risk>
            </FOLDER>
          </FOLDERS>
        </FOLDER>
      </FOLDERS>
    </FOLDER>
    <FOLDER>
      <Title>Market</Title>
      <FOLDERS>
        <FOLDER>
          <Title/>
          <FOLDERS>
            <FOLDER>
              <Title>Market Div</Title>
              <Risk>
                <TITLE>
                  Brand / reputation damage by company
                  environmental failure
                </TITLE>
                <CODE>Ad.358</CODE>
                <RISKYESNO1>0</RISKYESNO1>
                <RISKYESNO2>1</RISKYESNO2>
              </Risk>
              <Risk>
                <TITLE>
                  Supply of raw materials affected by
                  environmental failure
                </TITLE>
                <CODE>CK.324</CODE>
                <RISKYESNO1>0</RISKYESNO1>
                <RISKYESNO2>1</RISKYESNO2>
              </Risk>
              <Risk>
                <TITLE>
                  Loss of business through unattractive
                  product / service offerings
                </TITLE>
                <CODE>AABB01</CODE>
                <RISKYESNO1>0</RISKYESNO1>
                <RISKYESNO2>1</RISKYESNO2>
              </Risk>
              <Risk>
                <TITLE>Natural disaster</TITLE>
                <CODE>CCDD03</CODE>
                <RISKYESNO1>0</RISKYESNO1>
                <RISKYESNO2>1</RISKYESNO2>
              </Risk>
            </FOLDER>
            <FOLDER>
              <Title>Sales Div</Title>
              <Risk>
                <TITLE>Failure to achieve sales quota</TITLE>
                <CODE>S.001</CODE>
                <RISKYESNO1>0</RISKYESNO1>
                <RISKYESNO2>1</RISKYESNO2>
              </Risk>
            </FOLDER>
          </FOLDERS>
        </FOLDER>
      </FOLDERS>
    </FOLDER>
  </FOLDERS>
</FOLDER>
</FOLDERS>
</TmData>

我已经编写了以下XSLT文件,它将大部分时间都在那里,但我无法弄清楚如何防止FLODERS节点的重复。 XSLT看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>

<xsl:output method="xml" indent="yes"/>
<xsl:param name="rowSelector" select="local-name(//DocumentElement/*[1])"/>   

<xsl:template match="/TmData">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="DocumentElement"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="DocumentElement">
    <FOLDERS>
        <xsl:apply-templates mode="Elements"/>
    </FOLDERS>
</xsl:template>

<xsl:template name="Risks">       
  <xsl:apply-templates />      
</xsl:template>

<xsl:template match="@* | node()">
    <xsl:if test="not(starts-with(name(),'_'))">
        <xsl:copy>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:if>
</xsl:template>

<xsl:template match="RISK_x0020_FOLDER">
    <FOLDER>
        <Title>
            <xsl:value-of select="."/>
        </Title>        
        <xsl:call-template name="RiskTemplate">
            <xsl:with-param name="RiskFolderName" select ="."/>
        </xsl:call-template>
    </FOLDER>
</xsl:template>


<xsl:template match="FOLDER |FOLDER1 |FOLDER2 |FOLDER3">
    <xsl:param name="folderName"/>
    <xsl:param name="folderValue"/>
    <FOLDER>
        <Title>
            <xsl:value-of select="."/>
        </Title>
        <FOLDERS>
            <xsl:choose>
                <xsl:when test="starts-with(local-name(following-sibling::*[1]),'FOLDER')">
                    <xsl:apply-templates select="following-sibling::*[1]"/>                        
                </xsl:when>
            </xsl:choose>
            <xsl:choose>
                <xsl:when test="starts-with(local-name(following-sibling::*[1]),'RISK_x')">
                    <xsl:apply-templates select="following-sibling::*[1]"/>
                </xsl:when>
            </xsl:choose>
            </FOLDERS>
    </FOLDER>
</xsl:template>

<xsl:template name="RiskTemplate">
    <xsl:param name="RiskFolderName"/>
    <xsl:for-each select="//Risks[RISK_x0020_FOLDER=$RiskFolderName]">
        <Risk>
        <xsl:apply-templates select="@*"/>
        <xsl:apply-templates select="TITLE"/>
        <xsl:apply-templates select="CODE"/>            
        <xsl:apply-templates select="TYPE"/>
        <xsl:apply-templates select="DESCRIPTION"/>
        <xsl:apply-templates select="NOTES"/>
        <xsl:apply-templates select="RISKCATEGORY1"/>
        <xsl:apply-templates select="RISKCATEGORY2"/>
        <xsl:apply-templates select="RISKCATEGORY3"/>
        <xsl:apply-templates select="RISKCATEGORY4"/>
        <xsl:apply-templates select="RISKMULTISELECTCATEGORY"/>
        <xsl:apply-templates select="RISKNUMBERICVALUE1"/>
        <xsl:apply-templates select="RISKYESNO1"/>
        <xsl:apply-templates select="RISKYESNO2"/>
        <xsl:apply-templates select="WEIGHT"/>
        </Risk>
    </xsl:for-each>
</xsl:template>

<xsl:template match="node()" mode="Elements">
    <xsl:choose>
        <xsl:when test="local-name() = $rowSelector">
            <xsl:call-template name="Risks"/>
        </xsl:when>
    </xsl:choose>
</xsl:template>
</xsl:stylesheet>

我从转换得到的输出第一个块正确嵌套,但我无法弄清楚如何阻止转换查看它已经处理过的节点。有很多重复,这是我想要消除的。我一直试图解决这个问题超过一个星期,并且可以真正使用一些帮助。在此之前感谢所有XML / XSLT专家。

1 个答案:

答案 0 :(得分:1)

此模板可以解决您的问题。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  version="1.0"
  exclude-result-prefixes="msxsl">
  <xsl:output method="xml" indent="yes"/>

  <!--
    Initial template.
    -->
  <xsl:template match="/TmData">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:call-template name="folders">
        <xsl:with-param name="depth" select="0"/>
        <xsl:with-param name="risks" select="DocumentElement/Risks"/>
      </xsl:call-template>
    </xsl:copy>
  </xsl:template>

  <!--
    This template is applied to <Risks/>, once the folder for the risk
    has been built.
    -->
  <xsl:template match="Risks" mode="folder-content">
    <Risk>
      <xsl:copy-of select="@*|element()[not(starts-with(local-name(), '_') or contains(local-name(), 'FOLDER'))]"/>
    </Risk>
  </xsl:template>

  <!--
    Called to build out the folders at a given depth.
    params:
      depth: the current folder depth.
      risks: the risks that are in this folder.
    -->
  <xsl:template name="folders">
    <xsl:param name="depth"/>
    <xsl:param name="risks"/>
    <FOLDERS>
      <xsl:call-template name="folder">
        <xsl:with-param name="depth" select="$depth"/>
        <xsl:with-param name="risks" select="$risks"/>
      </xsl:call-template>
    </FOLDERS>
  </xsl:template>

  <!--
    Called to build a folder.  This template builds the folder for the first risk
    in the risks parameter.  It then creates the nested folders for that risk, by
    calling the folders template with the risks that are in the folder.  Finally,
    the template creates more folders at the same depth, by calling itself with
    the risks that were not in this folder.

    params:
      depth: the current folder depth.
      risks: the risks that are in this folder.
    -->
  <xsl:template name="folder">
    <xsl:param name="depth"/>
    <xsl:param name="risks"/>
    <xsl:if test="$risks">
      <xsl:variable name="element-name">
        <xsl:choose>
          <xsl:when test="$depth=0">FOLDER</xsl:when>
          <xsl:when test="$risks[1]/*[local-name()=concat('FOLDER', $depth)]">
            <xsl:value-of select="concat('FOLDER', $depth)"/>
          </xsl:when>
          <xsl:otherwise>RISK_x0020_FOLDER</xsl:otherwise>
        </xsl:choose>
      </xsl:variable>

      <!-- Build the folder for $risks[1] -->
      <FOLDER>
        <TITLE>
          <xsl:value-of select="$risks[1]/*[local-name()=$element-name]"/>
        </TITLE>
        <xsl:choose>
          <xsl:when test="$element-name='RISK_x0020_FOLDER'">
            <xsl:apply-templates select="$risks" mode="folder-content"/>
          </xsl:when>
          <xsl:otherwise>
            <!-- Build nested folders for all of the risks in the same folder as $risks[1]. -->
            <xsl:call-template name="folders">
              <xsl:with-param name="depth" select="$depth+1"/>
              <xsl:with-param name="risks" select="$risks[*[local-name()=$element-name]=$risks[1]/*[local-name()=$element-name]]"/>
            </xsl:call-template>
          </xsl:otherwise>
        </xsl:choose>
      </FOLDER>

      <!-- Build sibling folders for the risks that are not in the same folder as $risks[1] -->
      <xsl:call-template name="folder">
        <xsl:with-param name="depth" select="$depth"/>
        <xsl:with-param name="risks"
          select="$risks[not(*[local-name()=$element-name]=$risks[1]/*[local-name()=$element-name])]"/>
      </xsl:call-template>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

对于这样的情况,我会避免应用模板。创建一组要处理的东西然后使用递归调用模板来进行处理要容易得多。