Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sorting XSLT1.0中的变量排序_Sorting_Xslt - Fatal编程技术网

Sorting XSLT1.0中的变量排序

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处理器不喜欢在排序之前有一个变量 有什么想法吗?您不能

假设我有以下源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处理器不喜欢在排序之前有一个变量


有什么想法吗?

您不能按变量排序。计算两次标题:

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>