给定以下形式的输入 XML:
<root>
<alpha />
<beta />
<gamma />
</root>
我希望能够按照 XSL 样式表中定义的自定义顺序处理元素。我试过:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="http://tempurl.org"
exclude-result-prefixes="my">
<xsl:output omit-xml-declaration="yes" indent="yes" />
<!-- Elements should be processed in the following order: -->
<my:sorting>
<my:item id="beta" />
<my:item id="gamma" />
<my:item id="alpha" />
</my:sorting>
<xsl:template match="root">
<xsl:variable name="sortOrder" select="document('')/*/my:sorting/my:item" />
<xsl:apply-templates>
<xsl:sort select="count($sortOrder[@id=name()]/preceding-sibling::*)"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*">
<xsl:value-of select="name()" />
</xsl:template>
</xsl:stylesheet>
但这对排序没有影响。
这样的解决方案可能吗?我刚刚在 XSL 中犯了一些简单的错误吗?
(我知道涉及 string-length
和 substring-before
的不同解决方案,但我想知道如何让事情以类似的方式工作如果可能的话,与上面的内容相同。)
最佳答案
问题出在 xsl:sort
<xsl:sort select="count($sortOrder[@id=name()]/preceding-sibling::*)"/>
在表达式中,name()
是上下文相关的。它是应用于节点集 (sortOrder
) 的条件的一部分,因此将返回 sortOrder
元素的名称。本质上,它正在寻找名称等于其 id
属性的 sortOrder
元素。
要解决此问题,请使用 current()
函数
<xsl:sort select="count($sortOrder[@id=name(current())]/preceding-sibling::*)"/>
另一种方法,虽然不那么优雅,是将排序顺序定义为分隔字符串,如下所示:
<xsl:variable name="sortOrder" select="'|beta|alpha|gamma|'" />
然后你的排序表达式就变成这样了,主要是按元素名称在字符串中的位置进行排序。
<xsl:sort select="string-length(substring-before($sortOrder, concat('|', name(), '|')))" data-type="number"/>
在本例中,name()
不是条件的一部分,因此上下文是您要排序的元素。
关于xml - XML 元素的自定义排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26026999/