1

我有一个描述目录树的 xml。它可以有任意数量的子节点。这是一个例子:

<Catalog name="AccessoriesCatalog">
<Category Definition="AccessoriesCategory" name="1532" id="1532">
</Category>
<Category Definition="AccessoriesCategory" name="16115" id="16115">
    <ParentCategory>1532</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory" name="16116" id="16116">
    <ParentCategory>16115</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory" name="16126" id="16126">
    <ParentCategory>16115</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory" name="16131" id="16131">
    <ParentCategory>1532</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory" name="16132" id="16132">
    <ParentCategory>16131</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory" name="16136" id="16136">
    <ParentCategory>16131</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory" name="16139" id="16139">
    <ParentCategory>16131</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory" name="16144" id="16144">
    <ParentCategory>16131</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory" name="16195" id="16195">
    <ParentCategory>16131</ParentCategory>
</Category>

我需要能够按类别名称和 ParentCategory 对其进行排序。所有父类别应在 xml 中排在第一位,“叶类别”排在最后。在此示例中,xml 已排序。

上面的 xml 表示为树时是这样的
1532
-16115
--16116
--16126
-16131
--16132
--16136
--16139
--16144
--16195

我希望它像这样排序
1532
-16115
-16131
--16116
--16126
--16132
--16136
--16139
--16144
--16195

它可以是多个级别的子元素(在这种情况下只有一个 3 级树)。我希望所有 1 级元素首先出现在 xml 中,然后是所有 2 级元素,然后是所有 3 级元素等。

4

2 回答 2

2

这种转变

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kElemById" match="Category"
  use="@id"/>

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

 <xsl:template match="/*">
  <xsl:copy>
   <xsl:copy-of select="@*"/>

   <xsl:call-template name="sortHier">
    <xsl:with-param name="pNodes" select=
    "*[ParentCategory]"/>
    <xsl:with-param name="pParents" select=
    "*[not(ParentCategory)]"/>
   </xsl:call-template>
  </xsl:copy>
 </xsl:template>

 <xsl:template name="sortHier">
  <xsl:param name="pNodes"/>
  <xsl:param name="pParents"/>

  <xsl:apply-templates select=
   "$pParents|$pNodes[not($pParents)]">
   <xsl:sort select="@name"/>
  </xsl:apply-templates>

   <xsl:if test="$pNodes and $pParents">
    <xsl:variable name="vNewParents"
     select="key('kElemById', $pNodes/ParentCategory)
                [not(@id=$pParents/@id)]
     "/>

    <xsl:variable name="vNewChildren"
     select="$pNodes[not(@id=$vNewParents/@id)]"/>

    <xsl:call-template name="sortHier">
     <xsl:with-param name="pNodes"
          select="$vNewChildren"/>
     <xsl:with-param name="pParents"
          select="$vNewParents"/>
    </xsl:call-template>
   </xsl:if>
 </xsl:template>
</xsl:stylesheet>

应用于此 XML 文档时(基于提供的文档,但已打乱/未排序):

<Catalog name="AccessoriesCatalog">
    <Category Definition="AccessoriesCategory"
    name="16144" id="16144">
        <ParentCategory>16131</ParentCategory>
    </Category>
    <Category Definition="AccessoriesCategory"
    name="16116" id="16116">
        <ParentCategory>16115</ParentCategory>
    </Category>
    <Category Definition="AccessoriesCategory"
    name="16126" id="16126">
        <ParentCategory>16115</ParentCategory>
    </Category>
    <Category Definition="AccessoriesCategory"
    name="16131" id="16131">
        <ParentCategory>1532</ParentCategory>
    </Category>
    <Category Definition="AccessoriesCategory"
    name="16132" id="16132">
        <ParentCategory>16131</ParentCategory>
    </Category>
    <Category Definition="AccessoriesCategory"
    name="16136" id="16136">
        <ParentCategory>16131</ParentCategory>
    </Category>
    <Category Definition="AccessoriesCategory"
    name="16139" id="16139">
        <ParentCategory>16131</ParentCategory>
    </Category>
    <Category Definition="AccessoriesCategory"
    name="16115" id="16115">
        <ParentCategory>1532</ParentCategory>
    </Category>
    <Category Definition="AccessoriesCategory"
    name="1532" id="1532"></Category>
    <Category Definition="AccessoriesCategory"
    name="16195" id="16195">
        <ParentCategory>16131</ParentCategory>
    </Category>
</Catalog>

产生想要的正确结果

<Catalog name="AccessoriesCatalog">
   <Category Definition="AccessoriesCategory" name="1532" id="1532"/>
   <Category Definition="AccessoriesCategory" name="16115" id="16115">
      <ParentCategory>1532</ParentCategory>
   </Category>
   <Category Definition="AccessoriesCategory" name="16131" id="16131">
      <ParentCategory>1532</ParentCategory>
   </Category>
   <Category Definition="AccessoriesCategory" name="16116" id="16116">
      <ParentCategory>16115</ParentCategory>
   </Category>
   <Category Definition="AccessoriesCategory" name="16126" id="16126">
      <ParentCategory>16115</ParentCategory>
   </Category>
   <Category Definition="AccessoriesCategory" name="16132" id="16132">
      <ParentCategory>16131</ParentCategory>
   </Category>
   <Category Definition="AccessoriesCategory" name="16136" id="16136">
      <ParentCategory>16131</ParentCategory>
   </Category>
   <Category Definition="AccessoriesCategory" name="16139" id="16139">
      <ParentCategory>16131</ParentCategory>
   </Category>
   <Category Definition="AccessoriesCategory" name="16144" id="16144">
      <ParentCategory>16131</ParentCategory>
   </Category>
   <Category Definition="AccessoriesCategory" name="16195" id="16195">
      <ParentCategory>16131</ParentCategory>
   </Category>
</Catalog>

说明

  1. 递归调用命名模板,带有两个参数:“当前父节点集”(或“最后找到的父节点”)和当前(仍未处理)节点集。

  2. 停止条件:“当前父节点集”或“当前节点集”或两者都为空。在这里,我们输出(并排序@name)剩余的非空参数集。

  3. 递归步骤:“当前父母”的直系子女成为新的“当前父母”。其余的“当前节点”成为新的“当前节点”。如果没有当前父节点,则复制所有当前父节点或所有当前节点。

更新

在评论中,OP一直声称该解决方案正在处理小文件,

“但是当我尝试使用更多元素和更多级别的整个 xml 时,它不起作用。我拥有的 xml 大约是 8Mb,所以我不能在这里发布它。”

我让他(离线)提供 XML 文件,当我得到它们时,我已经确认这个解决方案在我提供的小型和大型(44000 行,700KB)文件上都没有问题。

除了 MSXML3 之外,更大文件的性能并不算太差

这是 44000 行文件的性能数据,在我的 8 岁(2GB RAM,3GHz 单核)PC 上看到:

MSXML3:                 91 sec.

MSXML6:                  6 sec.

AltovaXML (XMLSpy):      6 sec.

Saxon 6.5.4:             2 sec.

Saxon 9.1.05:            1.6 sec.

XslCompiledTransform     1.3 sec.

XQSharp:                 0.8 sec.
于 2011-04-22T04:02:06.863 回答
0

我想你的答案可以在这里找到:http: //www.programmersheaven.com/2/FAQ-XML-Sort-XML-By-Multiple-Attributes-XSLT

于 2011-04-21T19:37:15.353 回答