我有以下输入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,因此他们处于最底层。
答案 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>
使用相同的键,但在递归到下一级之前先完全输出每个级别。