2012-11-09 174 views
1

我对XML/XLST处理相当陌生,并且在必须使用版本1处理的环境中工作。我有一个从Excel电子表格中导出的XML文件。该文件看起来像这样:平面结构到多层嵌套结构的XSLT转换

<?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

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

<?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> 

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