首页 > 解决方案 > XSLT:按 ID 分组的无序平面 XML 到层次结构

问题描述

我正在努力使用 XSLT 1.0 创建一个转换,以按其 GUID 分层呈现我的数据。我有一个平面 XML,其中包含有关文件夹及其文件的数据,无序。我想以树形结构呈现这些数据。

平面 XML 无序:

<tns:Response>
 <tns:Result>
  <tns:ChildFolder>
     <tns:fFolderGUID>F3CF39082F7CD2DC9AAD9E34D6BFDA84</tns:fFolderGUID>
     <tns:fParentGUID>F050669AEA220E5B6D32FB92ABDB0080</tns:fParentGUID>
     <tns:fFolderName>Folder 0</tns:fFolderName>
     <tns:ChildFolder>
        <tns:fFolderGUID>91FEE5D69B8ABCE6DBEDE95344D962CE</tns:fFolderGUID>
        <tns:fParentGUID>D5F39DA59300A125437090D6E1A8BA89</tns:fParentGUID>
        <tns:fFolderName>Folder 5</tns:fFolderName>
     </tns:ChildFolder>
     <tns:ChildFolder>
        <tns:fFolderGUID>13A6EB7420E7586B21CC8F9CCED8AAA5</tns:fFolderGUID>
        <tns:fParentGUID>91FEE5D69B8ABCE6DBEDE95344D962CE</tns:fParentGUID>
        <tns:fFolderName>Folder 6</tns:fFolderName>
     </tns:ChildFolder>
     <tns:ChildFolder>
        <tns:fFolderGUID>99964626C187728B8A0823564126D091</tns:fFolderGUID>
        <tns:fParentGUID>F3CF39082F7CD2DC9AAD9E34D6BFDA84</tns:fParentGUID>
        <tns:fFolderName>Folder 1</tns:fFolderName>
     </tns:ChildFolder>
     <tns:ChildFolder>
        <tns:fFolderGUID>FEAD438C243F2AB6D3F273D4BBE701C3</tns:fFolderGUID>
        <tns:fParentGUID>F3CF39082F7CD2DC9AAD9E34D6BFDA84</tns:fParentGUID>
        <tns:fFolderName>Folder 2</tns:fFolderName>
     </tns:ChildFolder>
     <tns:ChildFolder>
        <tns:fFolderGUID>0F2F52149628A0029C436500873A1F1F</tns:fFolderGUID>
        <tns:fParentGUID>F3CF39082F7CD2DC9AAD9E34D6BFDA84</tns:fParentGUID>
        <tns:fFolderName>Folder 3</tns:fFolderName>
     </tns:ChildFolder>
     <tns:ChildFolder>
        <tns:fFolderGUID>D5F39DA59300A125437090D6E1A8BA89</tns:fFolderGUID>
        <tns:fParentGUID>99964626C187728B8A0823564126D091</tns:fParentGUID>
        <tns:fFolderName>Folder 4</tns:fFolderName>
     </tns:ChildFolder>
     <tns:ChildFile>
        <tns:fFileGUID>68E2DB7C43ED0C4C14D902398AD494FC</tns:fFileGUID>
        <tns:fParentGUID>D5F39DA59300A125437090D6E1A8BA89</tns:fParentGUID>
        <tns:dDocTitle>Document 4 - 1</tns:dDocTitle>
     </tns:ChildFile>
     <tns:ChildFile>
        <tns:fFileGUID>15D8716AAACDAEFDCBA77434BF62649D</tns:fFileGUID>
        <tns:fParentGUID>FEAD438C243F2AB6D3F273D4BBE701C3</tns:fParentGUID>
        <tns:dDocTitle>Document 2 - 2</tns:dDocTitle>
     </tns:ChildFile>
     <tns:ChildFile>
        <tns:fFileGUID>8DB55ACDC7518F0C2062456B0B467375</tns:fFileGUID>
        <tns:fParentGUID>FEAD438C243F2AB6D3F273D4BBE701C3</tns:fParentGUID>
        <tns:dDocTitle>Document 2 - 1</tns:dDocTitle>
     </tns:ChildFile>
     <tns:ChildFile>
        <tns:fFileGUID>AD7476CEF93E5C2A9F69DAFE6D42066D</tns:fFileGUID>
        <tns:fParentGUID>13A6EB7420E7586B21CC8F9CCED8AAA5</tns:fParentGUID>
        <tns:dDocTitle>Document 6 - 2</tns:dDocTitle>
     </tns:ChildFile>
     <tns:ChildFile>
        <tns:fFileGUID>00011D503C2691173A8A2C3004E9BE4E</tns:fFileGUID>
        <tns:fParentGUID>13A6EB7420E7586B21CC8F9CCED8AAA5</tns:fParentGUID>
        <tns:dDocTitle>Document 6 - 1</tns:dDocTitle>
     </tns:ChildFile>
     <tns:ChildFile>
        <tns:fFileGUID>CE82CD61E4D913817C3C795F1403C621</tns:fFileGUID>
        <tns:fParentGUID>F3CF39082F7CD2DC9AAD9E34D6BFDA84</tns:fParentGUID>
        <tns:dDocTitle>Document 0 - 1</tns:dDocTitle>
     </tns:ChildFile>
     <tns:ChildFile>
        <tns:fFileGUID>65DB227672A92D4DB1F153EB5EF5D41B</tns:fFileGUID>
        <tns:fParentGUID>F3CF39082F7CD2DC9AAD9E34D6BFDA84</tns:fParentGUID>
        <tns:dDocTitle>Document 0 - 2</tns:dDocTitle>
     </tns:ChildFile>
     <tns:ChildFile>
        <tns:fFileGUID>2099C99CE0B1BE9FA5A7152F21F23330</tns:fFileGUID>
        <tns:fParentGUID>99964626C187728B8A0823564126D091</tns:fParentGUID>
        <tns:dDocTitle>Document 1 - 1</tns:dDocTitle>
     </tns:ChildFile>
     <tns:ChildFile>
        <tns:fFileGUID>32F8C5F47475A093D1AE748552AD1A21</tns:fFileGUID>
        <tns:fParentGUID>99964626C187728B8A0823564126D091</tns:fParentGUID>
        <tns:dDocTitle>Document 1 - 2</tns:dDocTitle>
     </tns:ChildFile>
  </tns:ChildFolder>

我希望它在树结构中进行排序,如下所示:

<ns0:Response>
<ns0:Result>
  <ns0:ChildFolder>
     <ns0:fFolderGUID>F3CF39082F7CD2DC9AAD9E34D6BFDA84</ns0:fFolderGUID>
     <ns0:fParentGUID>F050669AEA220E5B6D32FB92ABDB0080</ns0:fParentGUID>
     <ns0:fFolderName>Folder 0</ns0:fFolderName>
     <ns0:ChildFile>
        <ns0:fFileGUID>CE82CD61E4D913817C3C795F1403C621</ns0:fFileGUID>
        <ns0:fParentGUID>F3CF39082F7CD2DC9AAD9E34D6BFDA84</ns0:fParentGUID>
        <ns0:dDocTitle>Document 0 - 1</ns0:dDocTitle>
     </ns0:ChildFile>
     <ns0:ChildFile>
        <ns0:fFileGUID>65DB227672A92D4DB1F153EB5EF5D41B</ns0:fFileGUID>
        <ns0:fParentGUID>F3CF39082F7CD2DC9AAD9E34D6BFDA84</ns0:fParentGUID>
        <ns0:dDocTitle>Document 0 - 2</ns0:dDocTitle>
     </ns0:ChildFile>
     <ns0:ChildFolder>
        <ns0:fFolderGUID>99964626C187728B8A0823564126D091</ns0:fFolderGUID>
        <ns0:fParentGUID>F3CF39082F7CD2DC9AAD9E34D6BFDA84</ns0:fParentGUID>
        <ns0:fFolderName>Folder 1</ns0:fFolderName>
        <ns0:ChildFile>
           <ns0:fFileGUID>2099C99CE0B1BE9FA5A7152F21F23330</ns0:fFileGUID>
           <ns0:fParentGUID>99964626C187728B8A0823564126D091</ns0:fParentGUID>
           <ns0:dDocTitle>Document 1 - 1</ns0:dDocTitle>
        </ns0:ChildFile>
        <ns0:ChildFile>
           <ns0:fFileGUID>32F8C5F47475A093D1AE748552AD1A21</ns0:fFileGUID>
           <ns0:fParentGUID>99964626C187728B8A0823564126D091</ns0:fParentGUID>
           <ns0:dDocTitle>Document 1 - 2</ns0:dDocTitle>
        </ns0:ChildFile>
        <ns0:ChildFolder>
           <ns0:fFolderGUID>D5F39DA59300A125437090D6E1A8BA89</ns0:fFolderGUID>
           <ns0:fParentGUID>99964626C187728B8A0823564126D091</ns0:fParentGUID>
           <ns0:fFolderName>Folder 4</ns0:fFolderName>
           <ns0:ChildFile>
              <ns0:fFileGUID>68E2DB7C43ED0C4C14D902398AD494FC</ns0:fFileGUID>
              <ns0:fParentGUID>D5F39DA59300A125437090D6E1A8BA89</ns0:fParentGUID>
              <ns0:dDocTitle>Document 4 - 1</ns0:dDocTitle>
           </ns0:ChildFile>
           <ns0:ChildFolder>
              <ns0:fFolderGUID>91FEE5D69B8ABCE6DBEDE95344D962CE</ns0:fFolderGUID>
              <ns0:fParentGUID>D5F39DA59300A125437090D6E1A8BA89</ns0:fParentGUID>
              <ns0:fFolderName>Folder 5</ns0:fFolderName>
              <ns0:ChildFolder>
                 <ns0:fFolderGUID>13A6EB7420E7586B21CC8F9CCED8AAA5</ns0:fFolderGUID>
                 <ns0:fParentGUID>91FEE5D69B8ABCE6DBEDE95344D962CE</ns0:fParentGUID>
                 <ns0:fFolderName>Folder 6</ns0:fFolderName>
                 <ns0:ChildFile>
                    <ns0:fFileGUID>AD7476CEF93E5C2A9F69DAFE6D42066D</ns0:fFileGUID>
                    <ns0:fParentGUID>13A6EB7420E7586B21CC8F9CCED8AAA5</ns0:fParentGUID>
                    <ns0:dDocTitle>Document 6 - 2</ns0:dDocTitle>
                 </ns0:ChildFile>
                 <ns0:ChildFile>
                    <ns0:fFileGUID>00011D503C2691173A8A2C3004E9BE4E</ns0:fFileGUID>
                    <ns0:fParentGUID>13A6EB7420E7586B21CC8F9CCED8AAA5</ns0:fParentGUID>
                    <ns0:dDocTitle>Document 6 - 1</ns0:dDocTitle>
                 </ns0:ChildFile>
              </ns0:ChildFolder>
           </ns0:ChildFolder>
        </ns0:ChildFolder>
     </ns0:ChildFolder>
     <ns0:ChildFolder>
        <ns0:fFolderGUID>FEAD438C243F2AB6D3F273D4BBE701C3</ns0:fFolderGUID>
        <ns0:fParentGUID>F3CF39082F7CD2DC9AAD9E34D6BFDA84</ns0:fParentGUID>
        <ns0:fFolderName>Folder 2</ns0:fFolderName>
        <ns0:ChildFile>
           <ns0:fFileGUID>15D8716AAACDAEFDCBA77434BF62649D</ns0:fFileGUID>
           <ns0:fParentGUID>FEAD438C243F2AB6D3F273D4BBE701C3</ns0:fParentGUID>
           <ns0:dDocTitle>Document 2 - 2</ns0:dDocTitle>
        </ns0:ChildFile>
        <ns0:ChildFile>
           <ns0:fFileGUID>8DB55ACDC7518F0C2062456B0B467375</ns0:fFileGUID>
           <ns0:fParentGUID>FEAD438C243F2AB6D3F273D4BBE701C3</ns0:fParentGUID>
           <ns0:dDocTitle>Document 2 - 1</ns0:dDocTitle>
        </ns0:ChildFile>
     </ns0:ChildFolder>
     <ns0:ChildFolder>
        <ns0:fFolderGUID>0F2F52149628A0029C436500873A1F1F</ns0:fFolderGUID>
        <ns0:fParentGUID>F3CF39082F7CD2DC9AAD9E34D6BFDA84</ns0:fParentGUID>
        <ns0:fFolderName>Folder 3</ns0:fFolderName>
     </ns0:ChildFolder>
  </ns0:ChildFolder>
 </ns0:Result>
</ns0:Response>

目前我正在使用 for-eaches 来测试文件夹/文件是否是父文件夹的子文件夹以及一个保存每个级别位置的变量。这样我只能呈现有限数量的关卡。必须有可能以更简单的方式做到这一点。感谢您帮助社区!

标签: xsltxslt-1.0

解决方案


定义一个或两个键来跟随 id 引用,然后处理/应用模板到所有引用的孩子:

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:tns="http://example.com/tns"
    exclude-result-prefixes="tns"
    version="1.0">

  <xsl:key name="child-files" match="tns:ChildFile" use="tns:fParentGUID"/>
  <xsl:key name="child-folders" match="tns:ChildFolder" use="tns:fParentGUID"/>

  <xsl:strip-space elements="*"/> 
  <xsl:output indent="yes"/>

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

  <xsl:template match="tns:ChildFolder">
    <xsl:copy>
        <xsl:apply-templates select="tns:*[not(self::tns:ChildFolder | self::tns:ChildFile)]"/>
        <xsl:apply-templates select="key('child-files', tns:fFolderGUID)"/>
        <xsl:apply-templates select="key('child-folders', tns:fFolderGUID)"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/gWmuiJt有一个在线示例。由于键适用于整个文档,如果用于键值的 id 在整个文档中不是唯一的并且有多个具有相同 id 的文件夹,则此方法将不起作用。但由于这些值似乎是 GUID,我猜你有独特的值。


推荐阅读