只有在满足某些条件时,我才需要更改执行for-each的顺序。
以下是我的XML:
<OptionList>
<Option name="My First Option" />
<Option name="My Second Option" />
</OptionList>
但是,在某些情况下,我的XML可以是这样的:
<OptionList>
<Option />
<Option name="My Second Option" />
</OptionList>
在我的XSL中,我正在做一个像这样的人:
<xsl:for-each select="//OptionList/Option">
{...}
</xsl:for-each>
我知道我可以在for-each:
中使用此行更改Option节点的顺序<xsl:sort select="position()" data-type="number" order="descending" />
问题是我希望我的订单只在第一个Option节点为空且没有name属性时才下降。否则,我想保留默认的升序。
关于如何实现这一点的任何意见?到目前为止,我尝试的所有内容都以“变量超出范围”或无效使用xpath函数结束。
答案 0 :(得分:5)
您可以使用hack根据条件更改排序顺序:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<result>
<xsl:for-each select="//OptionList/Option">
<xsl:sort data-type="number" order="ascending"
select="position()*(-2*number(not(//OptionList/Option[1]/@name))+1)"/>
<option>
<xsl:value-of select="@name"/>
</option>
</xsl:for-each>
</result>
</xsl:template>
</xsl:stylesheet>
黑客是number((true())
返回1而number(false())
返回0.因此,表达式
-2 * number(not(//OptionList/Option[1]/@name)) + 1
如果第一个1
元素具有option
属性,则评估为name
,否则评估为-1
。这用作反转排序顺序的因素。
答案 1 :(得分:1)
可以使用<xsl:sort>
轻松指定生成所需输出的顺序:
这很自然,很简单,几乎没有任何黑客攻击。
<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:variable name="vOrder" select=
"2*boolean(/*/Option[1]/@name)-1"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:for-each select="Option">
<xsl:sort data-type="number" select="$vOrder* position()"/>
<xsl:apply-templates select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
对此XML文档执行此转换时:
<OptionList>
<Option name="My First Option" />
<Option name="My Second Option" />
<Option name="My Third Option" />
</OptionList>
产生了想要的正确结果:
<OptionList>
<Option name="My First Option"/>
<Option name="My Second Option"/>
<Option name="My Third Option"/>
</OptionList>
现在对此XML文档执行相同的转换:
<OptionList>
<Option />
<Option name="My Second Option" />
<Option name="My Third Option" />
</OptionList>
再次产生想要的正确结果:
<OptionList>
<Option name="My Third Option"/>
<Option name="My Second Option"/>
<Option/>
</OptionList>
解释:变量$vOrder
以这样的方式定义,如果第一个-1
元素没有Option
,则为name
如果第一个+1
元素具有Option
属性,则属性为name
。在这里,我们使用false()
自动转换为0
和true()
转换为1
的事实。
我们还使用这样的事实:当正数(位置)增加的顺序中的每个数字的符号被反转时,新序列的顺序变得越来越小。
答案 2 :(得分:0)
检查第一个选项是否具有名称node
<xsl:if test="Option/[position()=1]/@name">sort here</xsl:test>