如何进行分层XSL排序?

时间:2016-11-18 13:20:41

标签: xml sorting xslt treeview hierarchy

我有以下输入XML:

<?xml version="1.0" encoding="UTF-8"?>
<soldiers>
    <soldier>
        <name>John</name>
        <supervisor>Marcus</supervisor>
    </soldier>
    <soldier>
        <name>Marcus</name>
        <supervisor>Mike</supervisor>
    </soldier>
    <soldier>
        <name>Frank</name>
        <supervisor>Marcus</supervisor>
    </soldier>
    <soldier>
        <name>Mike</name>
        <supervisor>Anna</supervisor>
    </soldier>
</soldiers>

现在我正在寻找一种基于supervisor标签对XML层次结构进行排序的方法。什么是最有效的方法?给定示例的结果应如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<soldiers>
    <soldier>
        <name>Mike</name>
        <supervisor>Anna</supervisor>
    </soldier>
    <soldier>
        <name>Marcus</name>
        <supervisor>Mike</supervisor>
    </soldier>
    <soldier>
        <name>John</name>
        <supervisor>Marcus</supervisor>
    </soldier>
    <soldier>
        <name>Frank</name>
        <supervisor>Marcus</supervisor>
    </soldier>
</soldiers>

所以迈克没有在这里列出的主管,所以他在顶部。马库斯&#39;主管是迈克,因此他在迈克之下。 John和Frank的主管是Marcus,因此他们处于最底层。

1 个答案:

答案 0 :(得分:1)

您可以使用key来关注参考:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:output indent="yes"/>

    <xsl:key name="ref" match="soldier" use="supervisor"/>

    <xsl:template match="soldiers">
        <xsl:copy>
            <xsl:apply-templates select="soldier[not(supervisor = ../soldier/name)]"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="soldier">
        <xsl:copy-of select="."/>
        <xsl:apply-templates select="key('ref', name)"/>
    </xsl:template>
</xsl:transform>

根据@ michael.hor257k的评论,你可能更想要

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
    xmlns:mf="http://example.com/mf" exclude-result-prefixes="mf">

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

    <xsl:key name="ref" match="soldier" use="supervisor"/>

    <xsl:variable name="main-root" select="/"/>

    <xsl:function name="mf:refs" as="element(soldier)*">
        <xsl:param name="input" as="element(soldier)*"/>
        <xsl:copy-of select="$input"/>
        <xsl:sequence select="if (key('ref', $input/name, $main-root)) then mf:refs(key('ref', $input/name, $main-root)) else ()"/>
    </xsl:function>

    <xsl:template match="soldiers">
        <xsl:copy>
            <xsl:sequence select="mf:refs(soldier[not(supervisor = ../soldier/name)])"/>
        </xsl:copy>
    </xsl:template>

</xsl:transform>

使用相同的键,但在递归到下一级之前先完全输出每个级别。