tags:

views:

178

answers:

3
+1  Q: 

Banding with xsl

I am beginning to think that the problem isn't with the banding code. Somehow count is not coming out correct. Could it be in either the xml, I have approx. 150 of the case-study nodes? Or can it be in the order in which I am doing the for-each and the if?

<!-- XML -->
<case-studies>

    <case-study> 
     <name>Company A</name>
     <solutionType>Mobility</solutionType>
     <solutionType>Convergence</solutionType>
              <solution category="Business services">Product</solution>  
     <solution category="Business services">Industry</solution>  
     <solution category="#">A-Z</solution>  
     <product>Product 1</product> 
    </case-study>
</case-studies>

I am trying to create a table that alternates gray rows within the for-each. The code below returns an eratic effect.

Thanks

    <xsl:sort select="../name" />
    <xsl:if test="@category[. = $solName]">

        <tr>
        <xsl:if test="(position() mod 2 = 1)">
      <xsl:attribute name="bgcolor">#e7e7e7</xsl:attribute>                
     </xsl:if>    

          <td class="cell1">

            <img src="/images/icons/infoWhite.gif" style="margin:3px 3px 0 0px;" id="{../name}" onmouseover="xstooltip_show('{../url}', '{../name}', 0, 10);" onmouseout="xstooltip_hide('{../url}');" />
            <div id="{../url}" class="xstooltip" style="margin:10px 0 0 10px;">
        <div class="floatLeft"><strong>Product(s):</strong></div> 
              <div class="margLeft10 floatLeft">
                <xsl:for-each select="../product/prodName">     
                    <div class="clearRight"><xsl:value-of select="."/></div>
                </xsl:for-each>          
                </div>
            </div> 
          </td> 
          <td class="cell2" style="padding-top:2px;">» <a href="{../url}"><xsl:value-of select="../name"/></a></td>
          <td class="cell3">
            <xsl:for-each select="../solutionType">      
                <div class="clearRight"><xsl:value-of select="."/></div>
      </xsl:for-each>                
          </td>
        </tr>
    </xsl:if>        
</xsl:for-each>
+3  A: 

This might work:

<xsl:for-each select="NewDataSet/authors">
<xsl:sort select="au_lname"/>

<xsl:if test="position()  mod 2 = 1">
<tr bgcolor="#aaccff">
    <td><xsl:value-of select="au_lname"/></td>
    <td><xsl:value-of select="au_fname"/></td>
    <td><xsl:value-of select="phone"/></td>
</tr>
</xsl:if>

<xsl:if test="position()  mod 2 = 0">
<tr bgcolor="#ffccaa">
    <td><xsl:value-of select="au_lname"/></td>
    <td><xsl:value-of select="au_fname"/></td>
    <td><xsl:value-of select="phone"/></td>
</tr>
</xsl:if>

</xsl:for-each>
Robert Harvey
This is excessively verbose. Maintaining the code would require updating it in two places. When there are only two cases (as is the case with modulus of 2) you should use the equivalent of if-else (`xsl:choose`). <xsl:choose> <xsl:when test="position() mod 2 = 1"> <!-- do Foo --> </xsl:when> <xsl:otherwise> <!-- do Bar --> </xsl:otherwise> </xsl:choose>
fearphage
+1  A: 

Looking at your XSLT, it suggests you are iterating over 'solution' elements in the . Is this correct?

I think the problem is that when you check the position() it will take into all previous solution elements regardless of whether previous ones have been ignored by the condition.

I can suggest two possibilities for solving this.

Firstly, try changing the test on the position() to a count() on the number of matching previous elements. For example:

<xsl:if test="(count(preceding-sibling::solution[@category=$solName]) mod 2 = 0)">

Alternatively, you could try add the test on the @category to the and removing the condition. For example:

<xsl:for-each select="solution[@category = $solName]">
    <xsl:sort select="../name" />
    <tr>
        <xsl:if test="(position() mod 2 = 1)">

I hope this makes sense!

Tim C
+1  A: 

The problem is that you need to use xsl:element to get xsl:attribute to function properly. You can't set the attribute of a static element. You have to get the xslt to generate the element for you.

<xsl:sort select="../name" />
  <xsl:if test="@category[. = $solName]">
    <!-- use xsl:element to create an element -->
    <xsl:element name="tr">
      <xsl:if test="position() mod 2 = 1">
        <!-- then xsl:attribute will function as expected -->
        <xsl:attribute name="bgcolor">#e7e7e7</xsl:attribute>
      </xsl:if>

      <!-- snip -->

    </xsl:element>
  </xsl:if>
</xsl:for-each>

I would suggest that you use class names and css (background-color) instead of inline styles:

<xsl:sort select="../name" />
  <xsl:if test="@category[. = $solName]">
    <!-- use xsl:element to create an element -->
    <xsl:element name="tr">
      <xsl:if test="position() mod 2 = 1">
        <!-- then xsl:attribute will function as expected -->
        <xsl:attribute name="class">alternateRow</xsl:attribute>
      </xsl:if>

      <!-- snip -->

    </xsl:element>
  </xsl:if>

Sample CSS (for my alternate solution):

.alternateRow { background-color: #e7e7e7; }

Also, you don't need to put parentheses around your tests. If I have multiple tests, I wrap them in parentheses for readability but with only one conditional, parentehses are convenitionally not added.

fearphage