在XSLT中,如何使用间接密钥进行排序?

时间:2010-05-20 13:41:43

标签: xslt attributes sorting

我无法让xsl:sort了解我引用的属性的范围。这是一个XML示例文档来说明:

<Root>
  <DrinkSelections>
    <Drink id=1000 name="Coffee"/>
    <Drink id=1001 name="Water"/>
    <Drink id=1002 name="Tea"/>
    <Drink id=1003 name="Almost But Not Quite Entirely Unlike Tea"/>
  </DrinkSelections>

  <CustomerOrder>
    <Drinks>
      <Drink oid="1001"/>
      <Drink oid="1002"/>
      <Drink oid="1003"/>
    </Drinks>
  </CustomerOrder

</Root>

我想生成CustomerOrder中包含的饮料列表(按名称排序)。这是我正在摆弄的XSLT代码:

<xsl:for-each select="/Root/CustomerOrder/Drinks/Drink">
   <xsl:sort select="/Root/DrinkSelections/Drink[@id = @oid]/@name"/>
   <xsl:variable name=var_oid select="@oid"/>
   <xsl:value-of select="/Root/DrinkSelections/Drink[@id = $var_oid]/@name"/>
</xsl:for-each>

显然,xsl:sort命令试图将“oid”属性应用于DrinkSelections中的Drink元素,而不是本地Drink元素。

我可以使用变量解决这个问题,就像在xsl:value-of语句中一样。但由于xsl:sort必须是xsl:for-each语句之后的第一个语句,因此我无法在xsl:variable之前插入xsl:sort语句。

有没有办法明确说明属性值应该来自“local”元素?

1 个答案:

答案 0 :(得分:2)

您缺少current()功能。

<xsl:for-each select="/Root/CustomerOrder/Drinks/Drink">
  <xsl:sort select="/Root/DrinkSelections/Drink[@id = current()/@oid]/@name"/>
  <xsl:value-of select="/Root/DrinkSelections/Drink[@id = current()/@oid]/@name"/>
</xsl:for-each>

但更突出的是,为了便于阅读,你缺少XSL密钥:

<xsl:key name="kDrinkById" match="DrinkSelections/Drink" use="@id" />

<!-- ... later ... -->
<xsl:for-each select="/Root/CustomerOrder/Drinks/Drink">
  <xsl:sort select="key('kDrinkById', @oid)/@name"/>
  <xsl:value-of select="key('kDrinkById', @oid)/@name"/>
</xsl:for-each>

您可能没有正确使用模板,因为如果您这样做,您的xsl:for-each选择表达式将不会从根目录开始。

<xsl:template match="Root">
  <xsl:apply-templates select="CustomerOrder/Drinks" />
</xsl:template>

<xsl:template match="CustomerOrder/Drinks">
  <xsl:apply-templates select="Drink">
    <xsl:sort select="key('kDrinkById', @oid)/@name"/>
  </xsl:apply-templates>
</xsl:template>

<xsl:template match="CustomerOrder/Drinks/Drink">
  <xsl:value-of select="key('kDrinkById', @oid)/@name"/>
</xsl:template>

请注意,我也删除了for-each。避免每个xsl:for-each都是迈向更好的XSLT代码的一步(非常罕见的例外情况适用)。