分层XSL如何排序?
How do hierarchical XSL sorting?
我有以下输入 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>
现在我正在寻找一种根据主管标签对 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>
这里没有列出迈克的主管,因此他排在最前面。 Marcus 的主管是 Mike,因此他隶属于 Mike。 John和Frank的上司是Marcus,所以排在最后。
您可以使用 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>
它使用相同的密钥,但在递归到下一个级别之前首先完全输出每个级别。
我有以下输入 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>
现在我正在寻找一种根据主管标签对 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>
这里没有列出迈克的主管,因此他排在最前面。 Marcus 的主管是 Mike,因此他隶属于 Mike。 John和Frank的上司是Marcus,所以排在最后。
您可以使用 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>
它使用相同的密钥,但在递归到下一个级别之前首先完全输出每个级别。