Vicky
Vicky

Reputation: 53

Counter generation following a range in xslt

I am trying to generate a counter and I do it successfully using the position() function in xslt.

How can I create a counter within a range -1001 - 9999 such that the first counter is 1001 in place of 1.

in put xml

<ROOT>
<Row>
    <Var>11</Var>
</Row>
<Row>
    <Var>11</Var>
</Row>
<Row>
    <Var>3</Var>
</Row>
<Row>
    <Var>43</Var>
</Row>
<Row>
    <Var>51</Var>
</Row>

and the desired o/p is

<ROOT>
<Row>
    <Var>11</Var>
    <seq>1001</seq>
</Row>
<Row>
    <Var>11</Var>
    <seq>1002</seq>
</Row>
<Row>
    <Var>3</Var>
    <seq>1003</seq>
</Row>
<Row>
    <Var>43</Var>
    <seq>1004</seq>
</Row>
<Row>
    <Var>51</Var>
    <seq>1005</seq>
</Row>
..

Thanks, Vicky

Upvotes: 0

Views: 428

Answers (3)

Michael Kay
Michael Kay

Reputation: 163458

Note that with XSLT 3.0 you can do

<seq>
    <xsl:number start-at="1001" />
</seq> 

Upvotes: 0

Martin Honnen
Martin Honnen

Reputation: 167706

Well, XPath 2 and later literally allows you to write 1000 to 9999 to create a sequence of those numbers. I am not sure how that fits into your problem as you haven't provided any context like input you have and output you want. In XSLT 3 (not 2) the xsl:number element often used to count or number things also has a start-at attribute, see https://www.w3.org/TR/xslt-30/#element-number.

As you seem to want to number elements from the input I think the right approach is to use xsl:number so with XSLT 3 you can simply do:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output indent="yes"/>

  <xsl:template match="Row">
      <xsl:copy>
          <xsl:apply-templates/>
          <seq>
              <xsl:number start-at="1001"/>
          </seq>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

http://xsltfiddle.liberty-development.net/jyyiVhq

with XSLT 2 you can of course use xsl:number in a variable and then at 1000 e.g.

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0"
  exclude-result-prefixes="xs">

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

  <xsl:output indent="yes"/>

  <xsl:template match="Row">
      <xsl:copy>
          <xsl:apply-templates/>
          <seq>
              <xsl:variable name="count" as="xs:integer"><xsl:number/></xsl:variable>
              <xsl:value-of select="$count + 1000"/>
          </seq>
      </xsl:copy>
  </xsl:template>
</xsl:transform>

http://xsltransform.hikmatu.com/jyyiVhn

I don't think it makes sense to use the to expression for your use case, it would rather be useful if you wanted to create a couple of new elements e.g.

  <xsl:template match="body">
      <xsl:copy>
          <xsl:for-each select="1001 to 1100">
              <seq>
                  <xsl:value-of select="."/>
              </seq>
          </xsl:for-each>
      </xsl:copy>
  </xsl:template>

Upvotes: 1

Vicky
Vicky

Reputation: 53

I achieved the req as below:

<xsl:template match="/">
    <ROOT>
        <xsl:apply-templates />
    </ROOT>
</xsl:template>
<xsl:template match="ROOT/Row"> 
    <Row>
        <Var>
            <xsl:value-of select="Var"/>
        </Var>
        <seq>
            <xsl:value-of select="1000 + position()" />
        </seq>          
    </Row>      
</xsl:template>

Upvotes: 1

Related Questions