XSL sort/if confusion

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • otis
    New Member
    • Nov 2008
    • 6

    XSL sort/if confusion

    Hi all,

    This is a small issue to make things prettier, but we all know how important that can be!

    I had an xsl:if to check if a node was the last one in a collection of nodes and if it was a horizontal divider would not be displayed underneath it. This worked a treat but now I'm trying to sort my data using xsl:sort. The if statement technically still works but now the node identified by last() could be anywhere in the output order. I only want to remove the horizontal divider at the end.

    Does anyone have any suggestions on how I can alter my if statement to reflect this? I imagine it is going to have to check that it is the latest year/month/day against every other sibling but I can't figure out how to do this properly.

    My sort:
    Code:
    <xsl:apply-templates select="primarycontent" mode="_1">
      <!-- Break down into components and sort ascending as a number -->
      <xsl:sort data-type="number" select="substring(detaildate,7,4)"/>
      <!-- year  -->
      <xsl:sort data-type="number" select="substring(detaildate,4,2)"/>
      <!-- month -->
      <xsl:sort data-type="number" select="substring(detaildate,1,2)"/>
      <!-- day   -->
    </xsl:apply-templates>
    My xsl:if that worked before:
    Code:
    <xsl:if test=".!=/page/primarycontent[last()]">
      <div class="divider2"></div>
    </xsl:if>
    Any suggestions?
  • Dormilich
    Recognized Expert Expert
    • Aug 2008
    • 8694

    #2
    idea – you could store the node set in a variable and test the variable's last element.... like <xsl:if test="$var[last()]"> (something like that)

    regards

    Comment

    • otis
      New Member
      • Nov 2008
      • 6

      #3
      That sounds interesting Dormilich... how would I store the sorted node set in a variable? I have to be honest, this is my first major foray into manually writing XSLT!

      Comment

      • Dormilich
        Recognized Expert Expert
        • Aug 2008
        • 8694

        #4
        without any testing I'd say
        Code:
        <xsl:template match="..." mode="_1">
          <xsl:variable name="var" select="."/> // change name as desired
        // further code here
        </xsl:template>
        at least that looks sensible to me (the element passed over to the template should be already sorted (that's what I assume after your apply-templates call)).

        regards

        PS you may have to declare the variable globally

        Comment

        • jkmyoung
          Recognized Expert Top Contributor
          • Mar 2006
          • 2057

          #5
          A couple ideas:
          Use a for-each to sort, and then use apply-templates. You could pass in a parameter to see if it's the last one.
          eg:

          [code=xml]
          <xsl:for-each select="primary content">
          <!-- Break down into components and sort ascending as a number -->
          <xsl:sort data-type="number" select="substri ng(detaildate,7 ,4)"/>
          <!-- year -->
          <xsl:sort data-type="number" select="substri ng(detaildate,4 ,2)"/>
          <!-- month -->
          <xsl:sort data-type="number" select="substri ng(detaildate,1 ,2)"/>
          <!-- day -->
          <xsl:apply-templates select="." mode="_1">
          <xsl:with-param name="last" select=".=last( )"/>
          </xsl:apply-templates>
          </xsl:for-each>
          ...
          ...
          <xsl:template match="primaryc ontent" mode="_1">
          <xsl:param name="last">
          [/code]

          Comment

          • otis
            New Member
            • Nov 2008
            • 6

            #6
            Originally posted by Dormilich
            idea – you could store the node set in a variable and test the variable's last element.... like <xsl:if test="$var[last()]"> (something like that)

            regards
            Unfortunately, my attempt at this meant every single one thought that it was $var[last()] because I had to put the variable declaration inside the xsl:template for the repeating group that has been sorted... so "." is a single node rather that the sorted group. I also tried "./..".

            With the way it is sorted and that fact that xsl:variable is not valid within xsl:apply-templates I don't see another place to put the xsl:variable where it would be effective. Am I being really useless on this one?

            jkmyoung, I don't understand your suggestion but I'll give it a try!

            Comment

            • jkmyoung
              Recognized Expert Top Contributor
              • Mar 2006
              • 2057

              #7
              Rechecked the concept. You don't even need a parameter.
              [code=xml]
              <xsl:for-each select="your nodes...">
              <xsl:sort select="..."/>
              <xsl:sort select="..."/>
              <xsl:sort select="..."/>
              <xsl:apply-templates select="."/>
              </xsl:for-each>

              <xsl:template match="nodes">
              ...
              <xsl:if test="position( ) != last()">
              display your horizontal divider
              </xsl:if>

              [/code]

              The for-each automatically reorders the nodes with the sorting. Then you can just check if the node is the last one the same way that you used to.

              Comment

              • otis
                New Member
                • Nov 2008
                • 6

                #8
                Unfortunately when I try that position() and last() are always equal to 1 because you're only passing a single node to the apply-templates request.

                However, I moved the if statement into the for-each as shown below and it worked a treat!

                Thanks for your help guys.

                Code:
                <xsl:for-each select="primarycontent">
                  <!-- Break date down into components and sort ascending as a number -->
                  <xsl:sort data-type="number" select="substring(detaildate,7,4)"/>
                  <!-- year  -->
                  <xsl:sort data-type="number" select="substring(detaildate,4,2)"/>
                  <!-- month -->
                  <xsl:sort data-type="number" select="substring(detaildate,1,2)"/>
                  <!-- day   -->
                  <xsl:apply-templates select="." mode="_1" />
                  <!-- Add a conditional test to hide the divider for the last entry -->
                  <xsl:if test="position() != last()">
                    <div class="divider2"></div>
                  </xsl:if>
                </xsl:for-each>

                Comment

                Working...