Sorting XSLT1.0中的变量排序
假设我有以下源XML:Sorting XSLT1.0中的变量排序,sorting,xslt,Sorting,Xslt,假设我有以下源XML: <products> <product type="x" titleOne="some title" titleTwo="some other title"/> <product type="y" titleOne="one more title" titleTwo="and another title"/> </products> 但不幸的是,我的XSLT处理器不喜欢在排序之前有一个变量 有什么想法吗?您不能
<products>
<product type="x" titleOne="some title" titleTwo="some other title"/>
<product type="y" titleOne="one more title" titleTwo="and another title"/>
</products>
但不幸的是,我的XSLT处理器不喜欢在排序之前有一个变量
有什么想法吗?您不能按变量排序。计算两次标题: XSLT1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/products">
<xsl:copy>
<xsl:for-each select="product">
<xsl:sort select="@titleOne[../@type='x'] | @titleTwo[../@type='y']"/>
<product title="{@titleOne[../@type='x'] | @titleTwo[../@type='y']}"/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
或者使用变量对标题正确的产品进行预处理,然后对结果进行排序:
XSLT1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/products">
<!-- first pass -->
<xsl:variable name="products">
<xsl:for-each select="product">
<product>
<xsl:attribute name="title">
<xsl:choose>
<xsl:when test="@type='x'">
<xsl:value-of select="@titleOne"/>
</xsl:when>
<xsl:when test="@type='y'">
<xsl:value-of select="@titleTwo"/>
</xsl:when>
</xsl:choose>
</xsl:attribute>
</product>
</xsl:for-each>
</xsl:variable>
<!-- output -->
<xsl:copy>
<xsl:for-each select="exsl:node-set($products)/product">
<xsl:sort select="@title"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我将尝试回答以下子问题: 或者,在XSLT2/3中是否有这样做的方法 在2.0中执行此操作的一种方法是将排序键定义为函数:
<xsl:function name="f:myTitle" as="xs:string">
<xsl:param name="product" as="element(product)"/>
<xsl:choose>
<xsl:when test="$product/@type = 'x'">
<xsl:value-of select="$product/@titleOne"/>
</xsl:when>
<xsl:when test="$product/@type = 'y'">
<xsl:value-of select="$product/@titleTwo"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$product/subproduct/@title"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
“选择的标题取决于类型属性。”具体如何?您需要显示
,让我们知道是否可以直接为xsl:sort select
。添加了逻辑。在XSLT 2.0中,您可以将该逻辑放入用xsl:function
定义的函数中,然后在需要使用该值的地方调用它。此外,XSLT/XPath 2.0还有一个if
表达式,因此您可以将逻辑编写得更紧凑、更直接,而不是更详细的xsl:choose/xsl:when
。为什么要将问题标记为“saxon”并要求XSLT 1.0解决方案?我正在删除Saxon标记,因为这里没有特定于Saxon的内容。msxml也是如此。
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/products">
<!-- first pass -->
<xsl:variable name="products">
<xsl:for-each select="product">
<product>
<xsl:attribute name="title">
<xsl:choose>
<xsl:when test="@type='x'">
<xsl:value-of select="@titleOne"/>
</xsl:when>
<xsl:when test="@type='y'">
<xsl:value-of select="@titleTwo"/>
</xsl:when>
</xsl:choose>
</xsl:attribute>
</product>
</xsl:for-each>
</xsl:variable>
<!-- output -->
<xsl:copy>
<xsl:for-each select="exsl:node-set($products)/product">
<xsl:sort select="@title"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<xsl:function name="f:myTitle" as="xs:string">
<xsl:param name="product" as="element(product)"/>
<xsl:choose>
<xsl:when test="$product/@type = 'x'">
<xsl:value-of select="$product/@titleOne"/>
</xsl:when>
<xsl:when test="$product/@type = 'y'">
<xsl:value-of select="$product/@titleTwo"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$product/subproduct/@title"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<xsl:for-each select="product">
<xsl:sort select="f:myTitle(.)"/>
<product title="{f:myTitle(.)}"/>
</xsl:for-each>
<xsl:variable name="product-map"
select="map:merge(product!map{f:myTitle(.) : .})"/>
<xsl:for-each select="map:keys($product-map)">
<xsl:sort select="."/>
<product title="{.}">
<xsl:apply-templates select="$product-map(.)"/>
</product>
</xsl:for-each>
<xsl:for-each-group select="product" group-by="f:myTitle(.)">
<xsl:sort select="current-grouping-key()"/>
<product title="{current-grouping-key()}"/>
</xsl:for-each>
<xsl:for-each select="sort(product![f:myTitle#1, .],
function($p){$p(1)})">
<product title="{.(1)}">
<xsl:apply-templates select=".(2)"/>
</product>
</xsl:for-each>