N0000B
N0000B

Reputation: 449

XSLT - Previous Value & Increment Counter

I am trying to implement some php code logic, into XSLT.

The xml structure looks like

Input:

<parent>
    <child>
        <id>1</id>
        <value>11</value>
    </child>
    <child>
        <id>2</id>
        <value>22</value>
    </child>
    <child>
        <id></id>
        <value>22</value>
    </child>
    <child>
        <id></id>
        <value>00</value>
    </child>
    <child>
        <id></id>
        <value>00</value>
    </child>
<parent>

The sudo code in php (logic) I am trying to implement in XSLT is as follows:

var Index = 1;
for each "child"{
    if( "id" is not empty ){
        Index += "id" + 1;
    }else{
        if( previous "value" == current "value" ){
            "id" = Index;
            Index++;
        }else{
            "id" = 1;
            Index = 2;
        }
    }
}

As I understand in XSLT we can't have a counter/variable that we can update on each iteration. I believe I can use the preceding-sibling to compare the previous value with the current value, but how to calculate the index at that point? I can use XSLT 2.0, if that makes it easier/simpler.

Any ideas suggestions?

The output after the transform should look as follows:

Output:

<parent>
    <child>
        <id>1</id>
        <value>11</value>
    </child>
    <child>
        <id>2</id>
        <value>22</value>
    </child>
    <child>
        <id>6</id> <!-- "id" = "Index" calculated so far, since current value (22) = previous value (22) -->
        <value>22</value>
    </child>
    <child>
        <id>1</id> <!-- "id" = 1 since current value (00) != previous value (22) -->
        <value>00</value>
    </child>
    <child>
        <id>2</id> <!-- "id" = "Index" calculated so far, since currnet value (00) = previous value (00) --> 
        <value>00</value>
    </child>
<parent>

Upvotes: 1

Views: 466

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167716

Here is an attempt using XSLT 3 and xsl:iterate:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    expand-text="yes"
    version="3.0">

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

  <xsl:template match="parent">
      <xsl:copy>
          <xsl:iterate select="child">
              <xsl:param name="index" select="1"/>
              <xsl:param name="previous-value" select="()"/>
              <xsl:variable name="value" select="value"/>
              <xsl:variable name="id" 
                select="(id[has-children()], if ($value = $previous-value) then $index else 1)[1]"/>
              <xsl:variable name="index"
                select="if (id[has-children()])
                        then $index + $id + 1
                        else if ($value = $previous-value)
                        then $index + 1
                        else 2"/>
              <xsl:apply-templates select=".">
                  <xsl:with-param name="id" select="$id" tunnel="yes"/>
              </xsl:apply-templates>
              <xsl:next-iteration>
                  <xsl:with-param name="index" select="$index"/>
                  <xsl:with-param name="previous-value" select="$value"/>
              </xsl:next-iteration>
          </xsl:iterate>
      </xsl:copy>
  </xsl:template>

  <xsl:template match="id[not(has-children())]">
      <xsl:param name="id" tunnel="yes"/>
      <xsl:copy>{$id}</xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Upvotes: 1

Related Questions