简体   繁体   中英

Mimicking position(node-set) in XSLT 1.0?

XSLT 2.0 offers the benefit of passing a node-set param as part of the position() function. Unfortunately, that is not available in XSLT 1.0. Is there a way to mimic this behavior?

For example, given this XML:

<wishlists>
  <wishlist name="Games">
    <product name="Crash Bandicoot"/>
    <product name="Super Mario Brothers"/>
    <product name="Sonic the Hedgehog"/>
  </wishlist>
  <wishlist name="Movies">
    <product name="Back to the Future"/>
  </wishlist>
</wishlists>

and this XSLT 2.0:

<xsl:value-of select="position(/wishlists/wishlist/product)"/>

the value "4" would be returned when processing the final "Back to the Future" node.

Unfortunately, the closest I seem to be able to get with XSLT 1.0 is the following:

<xsl:template match="product">
  <xsl:value-of select="position()"/>
</xsl:template>

However, I would get a value of "1" in the same "Back to the Future" node, as opposed to the "4" value that I really want.

You can use the preceding axis .

This XSLT 1.0 stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="product">
    <product position="{count(preceding::product) + 1}">
      <xsl:apply-templates select="@*"/>
    </product>    
  </xsl:template>

</xsl:stylesheet>

Applied to your XML input produces:

<wishlists>
   <wishlist name="Games">
      <product position="1" name="Crash Bandicoot"/>
      <product position="2" name="Super Mario Brothers"/>
      <product position="3" name="Sonic the Hedgehog"/>
   </wishlist>
   <wishlist name="Movies">
      <product position="4" name="Back to the Future"/>
   </wishlist>
</wishlists>

XSLT 2.0 offers the benefit of passing a node-set param as part of the position() function.

This statement is wrong. The position() function has no arguments -- either in XPath 1.0 or in XPath 2.0, which XSLT 2.0 uses.

What you want is :

count(preceding::product) +1

or, alternatively, the xsl:number instruction can be used.

Here is a demonstration of both these methods :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:variable name="vLastProd" select=
  "//product[@name='Back to the Future']"/>

 <xsl:template match="/">
     <xsl:value-of select="count($vLastProd/preceding::product) +1"/>
=========
<xsl:text/>
   <xsl:apply-templates select="$vLastProd"/>
 </xsl:template>

 <xsl:template match="product">
   <xsl:number level="any" count="product"/>    
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document :

<wishlists>
    <wishlist name="Games">
        <product name="Crash Bandicoot"/>
        <product name="Super Mario Brothers"/>
        <product name="Sonic the Hedgehog"/>
    </wishlist>
    <wishlist name="Movies">
        <product name="Back to the Future"/>
    </wishlist>
</wishlists>

the wanted, correct result is obtained using both methods -- and output :

4
=========
4

Note : The result of xsl:number needs to be captured inside the body of a variable, if it will not be output directly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM