Ryan
Ryan

Reputation: 1

xsl counting and xpath syntax

I have a table of projects created in SharePoint 2010. I am trying to create reporting for management and need to get counts of various fields. I have used xsl to get the values of fields when viewing single items, so I am fairly familiar with the language. However, I cannot find a good explanation of the syntax for counting multiple items.

I have a table like this:

<table>
  <tr>
    <th class="ms-vb2">
        Project Title
    </th>
    <th class="ms-vb2">
        Project Leader
    </th>
    <th class="ms-vb2">
        Project Status
    </th>
  </tr> 
  <tr>
    <td class="ms-vb2">
        Project Title 1
    </td>
    <td class="ms-vb2">
        Project Leader 1
    </td>
    <td class="ms-vb2">
        Completed
    </td>
  </tr>
  <tr>
    <td class="ms-vb2">
        Project Title 2
    </td>
    <td class="ms-vb2">
        Project Leader 1
    </td>
    <td class="ms-vb2">
        Withdrawn
    </td>
  </tr>
  <tr>
    <td class="ms-vb2">
        Project Title 3
    </td>
    <td class="ms-vb2">
        Project Leader 2
    </td>
    <td class="ms-vb2">
        Completed
    </td>
  </tr>
  <!--About 100 more rows-->
</table>

There is a lot of nesting going on, so I am having difficulty targeting specific areas and I have very little control over the html due to this being generated by SharePoint.

Here is the reporting table I am trying to create using XSL:

<table id="FourBlockerHead" class="ClearBlockFloat">
  <tr>
    <th>Completed Count</th>
    <th>Withdrawn Count</th>
    <th>On Hold Count</th>
  </tr>
  <tr>
    <td>
      <xsl:value-of select="count(../td[@ms-vb2='Completed'])" /><!--Should be 2-->
    </td>
    <td>
      <xsl:value-of select="count(../td[@ms-vb2='Withdrawn'])" /><!--Should be 1-->
    </td>
    <td>
      <xsl:value-of select="count(../td[@ms-vb2='On Hold'])" /><!--Should be 0-->
    </td>
  </tr>
</table>

I know there is a problem with my XPATH syntax, but I cannot figure it out.

Upvotes: 0

Views: 52

Answers (2)

michael.hor257k
michael.hor257k

Reputation: 116959

Instead of:

<xsl:value-of select="count(../td[@ms-vb2='Completed')" />

try:

<xsl:value-of select="count(//td[@class='ms-vb2'][normalize-space()='Completed'])" />

and likewise for the other two.

Notes:

  • You did not provide the context, so I have changed the path to an absolute one, that counts all nodes in the entire document;

  • You don't have an attribute named ms-vb2;

  • You need to trim the whitespace in the data cell before comparing ot to a string with no whitespace.


The following stylesheet:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:template match="table">
    <table id="FourBlockerHead" class="ClearBlockFloat">
        <tr>
            <th>Completed Count</th>
            <th>Withdrawn Count</th>
            <th>On Hold Count</th>
        </tr>
        <tr>
            <td>
                <xsl:value-of select="count(//td[@class='ms-vb2'][normalize-space()='Completed'])" />
            </td>
            <td>
                <xsl:value-of select="count(//td[@class='ms-vb2'][normalize-space()='Withdrawn'])" />
            </td>
            <td>
                <xsl:value-of select="count(//td[@class='ms-vb2'][normalize-space()='On Hold'])" />
            </td>
        </tr>
    </table>
</xsl:template>

</xsl:stylesheet>

applied to your input example, will return:

<table id="FourBlockerHead" class="ClearBlockFloat">
   <tr>
      <th>Completed Count</th>
      <th>Withdrawn Count</th>
      <th>On Hold Count</th>
   </tr>
   <tr>
      <td>2</td>
      <td>1</td>
      <td>0</td>
   </tr>
</table>

Upvotes: 1

zx485
zx485

Reputation: 29022

A complete XSLT would look like this:

<?xml version="1.0" encoding="utf-8"?>

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

  <xsl:template match="/table">
    <html>
      <body>
        <table id="FourBlockerHead" class="ClearBlockFloat" border="1">
          <tr>
            <th>Completed Count</th>
            <th>Withdrawn Count</th>
            <th>On Hold Count</th>
          </tr>
          <xsl:for-each select="tr">
          <tr>
            <td>
              <xsl:value-of select="count(td[@class='ms-vb2' and normalize-space(text())='Completed'])" /><!--Should be 2-->
            </td>
            <td>
              <xsl:value-of select="count(td[@class='ms-vb2' and normalize-space(text())='Withdrawn'])" /><!--Should be 1-->
            </td>
            <td>
              <xsl:value-of select="count(td[@class='ms-vb2' and normalize-space(text())='On Hold'])" /><!--Should be 0-->
            </td>
          </tr>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>

</xsl:stylesheet>

You can include this in your source XML file with

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="source.xslt"?>

in your XML file to get a well formatted HTML output.

The output would look like this:

enter image description here

Upvotes: 1

Related Questions