Question

I've read through quite a few other questions on this topic, and according to the answers I've read elsewhere on the site I think I'm doing this correctly, but it still doesn't work.

I have an XHTML file that I've run through JTidy and run an XPath to select a single table node from that XHTML. That all works fine, and XPath is able to select the table just fine, it returns the following snippet of XML:

<table xmlns="http://www.w3.org/1999/xhtml" align="left" border="1" cellpadding="3" cellspacing="3" id="ctl07_tblMain" rules="rows" style="border-color:Green; border-style:solid; border-width:1px;" summary="Table is for layout purpose only">
  <tr>
    <th class="GridViewHeader" colspan="19" style="font-weight:bold; text-align:center">Select an arrival date
to continue.</th>
  </tr>
  <tr class="altCampArea">
    <td align="center" width="400">Site Type</td>
    <td align="center"> Pet </td>
    <td align="center">Electric</td>
    <td align="center">Water</td>
    <td align="center">Sewer</td>
    <td align="center" title="Friday, 02/07/2014" width="20">
      <a href="#" onclick="javascript:closeAndRedirect(&quot;2/7/2014&quot;,&quot;SearchCriteria.aspx&quot;); return false;">02/07</a>
    </td>
    <td align="center" title="Saturday, 02/08/2014" width="20">
      <a href="#" onclick="javascript:closeAndRedirect(&quot;2/8/2014&quot;,&quot;SearchCriteria.aspx&quot;); return false;">02/08</a>
    </td>
    <td align="center" title="Sunday, 02/09/2014" width="20">
      <a href="#" onclick="javascript:closeAndRedirect(&quot;2/9/2014&quot;,&quot;SearchCriteria.aspx&quot;); return false;">02/09</a>
    </td>
    <td align="center" title="Monday, 02/10/2014" width="20">
      <a href="#" onclick="javascript:closeAndRedirect(&quot;2/10/2014&quot;,&quot;SearchCriteria.aspx&quot;); return false;">02/10</a>
    </td>
    <td align="center" title="Tuesday, 02/11/2014" width="20">
      <a href="#" onclick="javascript:closeAndRedirect(&quot;2/11/2014&quot;,&quot;SearchCriteria.aspx&quot;); return false;">02/11</a>
    </td>
    <td align="center" title="Wednesday, 02/12/2014" width="20">
      <a href="#" onclick="javascript:closeAndRedirect(&quot;2/12/2014&quot;,&quot;SearchCriteria.aspx&quot;); return false;">02/12</a>
    </td>
    <td align="center" title="Thursday, 02/13/2014" width="20">
      <a href="#" onclick="javascript:closeAndRedirect(&quot;2/13/2014&quot;,&quot;SearchCriteria.aspx&quot;); return false;">02/13</a>
    </td>
    <td align="center" title="Friday, 02/14/2014" width="20">
      <a href="#" onclick="javascript:closeAndRedirect(&quot;2/14/2014&quot;,&quot;SearchCriteria.aspx&quot;); return false;">02/14</a>
    </td>
    <td align="center" title="Saturday, 02/15/2014" width="20">
      <a href="#" onclick="javascript:closeAndRedirect(&quot;2/15/2014&quot;,&quot;SearchCriteria.aspx&quot;); return false;">02/15</a>
    </td>
    <td align="center" title="Sunday, 02/16/2014" width="20">
      <a href="#" onclick="javascript:closeAndRedirect(&quot;2/16/2014&quot;,&quot;SearchCriteria.aspx&quot;); return false;">02/16</a>
    </td>
    <td align="center" title="Monday, 02/17/2014" width="20">
      <a href="#" onclick="javascript:closeAndRedirect(&quot;2/17/2014&quot;,&quot;SearchCriteria.aspx&quot;); return false;">02/17</a>
    </td>
    <td align="center" title="Tuesday, 02/18/2014" width="20">
      <a href="#" onclick="javascript:closeAndRedirect(&quot;2/18/2014&quot;,&quot;SearchCriteria.aspx&quot;); return false;">02/18</a>
    </td>
    <td align="center" title="Wednesday, 02/19/2014" width="20">
      <a href="#" onclick="javascript:closeAndRedirect(&quot;2/19/2014&quot;,&quot;SearchCriteria.aspx&quot;); return false;">02/19</a>
    </td>
    <td align="center" title="Thursday, 02/20/2014" width="20">
      <a href="#" onclick="javascript:closeAndRedirect(&quot;2/20/2014&quot;,&quot;SearchCriteria.aspx&quot;); return false;">02/20</a>
    </td>
  </tr>
  <tr>
    <td align="left" width="400">CEDAR GROVE-WATER ONLY CAMPSITE</td>
    <td align="center">Yes</td>
    <td align="center">No</td>
    <td align="center">Yes</td>
    <td align="center">No</td>
    <td align="center">11</td>
    <td align="center">11</td>
    <td align="center">11</td>
    <td align="center">11</td>
    <td align="center">11</td>
    <td align="center">11</td>
    <td align="center">11</td>
    <td align="center">11</td>
    <td align="center">11</td>
    <td align="center">11</td>
    <td align="center">11</td>
    <td align="center">11</td>
    <td align="center">11</td>
    <td align="center">11</td>
  </tr>
  <tr class="altCampArea">
    <td align="left" width="400">LARGE TRAILER AREA-ELECTRIC &amp;
WATER CAMPSITE 50AMP</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">No</td>
    <td align="center">12</td>
    <td align="center">12</td>
    <td align="center">12</td>
    <td align="center">12</td>
    <td align="center">12</td>
    <td align="center">12</td>
    <td align="center">11</td>
    <td align="center">9</td>
    <td align="center">9</td>
    <td align="center">10</td>
    <td align="center">13</td>
    <td align="center">13</td>
    <td align="center">13</td>
    <td align="center">13</td>
  </tr>
  <tr>
    <td align="left" width="400">LARGE TRAILER
AREA-SEWER,ELECT&amp;WATER HOST 50AMP</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
  </tr>
  <tr class="altCampArea">
    <td align="left" width="400">OAK GROVE-SEWER,ELECT&amp;WATER
30AMP</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">2</td>
    <td align="center">3</td>
    <td align="center">3</td>
    <td align="center">3</td>
    <td align="center">3</td>
    <td align="center">3</td>
    <td align="center">3</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">2</td>
    <td align="center">2</td>
    <td align="center">2</td>
    <td align="center">3</td>
  </tr>
  <tr>
    <td align="left" width="400">PECAN GROVE-ELECTRIC &amp; WATER
CAMPSITE 20FT 50AMP</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">No</td>
    <td align="center">8</td>
    <td align="center">8</td>
    <td align="center">9</td>
    <td align="center">9</td>
    <td align="center">9</td>
    <td align="center">9</td>
    <td align="center">9</td>
    <td align="center">9</td>
    <td align="center">9</td>
    <td align="center">9</td>
    <td align="center">9</td>
    <td align="center">9</td>
    <td align="center">9</td>
    <td align="center">9</td>
  </tr>
  <tr class="altCampArea">
    <td align="left" width="400">PECAN GROVE-ELECTRIC &amp; WATER
CAMPSITE 25FT 50AMP</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">No</td>
    <td align="center">10</td>
    <td align="center">10</td>
    <td align="center">10</td>
    <td align="center">10</td>
    <td align="center">10</td>
    <td align="center">10</td>
    <td align="center">10</td>
    <td align="center">10</td>
    <td align="center">10</td>
    <td align="center">10</td>
    <td align="center">10</td>
    <td align="center">10</td>
    <td align="center">10</td>
    <td align="center">10</td>
  </tr>
  <tr>
    <td align="left" width="400">PECAN GROVE-ELECTRIC &amp; WATER TENT
ONLY 50AMP</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">No</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
  </tr>
  <tr class="altCampArea">
    <td align="left" width="400">PECAN GROVE-SEWER,ELECT&amp;WATER HOST
50AMP</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
  </tr>
  <tr>
    <td align="left" width="400">WAGON CIRCLE-GROUP TRAILER AREA
50AMP</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">No</td>
    <td align="center">35</td>
    <td align="center">35</td>
    <td align="center">35</td>
    <td align="center">35</td>
    <td align="center">35</td>
    <td align="center">35</td>
    <td align="center">35</td>
    <td align="center">35</td>
    <td align="center">35</td>
    <td align="center">35</td>
    <td align="center">35</td>
    <td align="center">35</td>
    <td align="center">35</td>
    <td align="center">35</td>
  </tr>
  <tr class="altCampArea">
    <td align="left" width="400">WAGON CIRCLE-SEWER,ELECT&amp;WATER
PREMIUM 50AMP</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">Yes</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
    <td align="center">0</td>
  </tr>
</table>

Then I try to process it using this XSLT:

<xslt:stylesheet xmlns:xslt="http://www.w3.org/1999/XSL/Transform" xmlns:csw-xform="http://www.compositesw.com/2003/xform" xmlns:ns1="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
  <xslt:template match="/">
    <xslt:variable name="_value"/>
    <xslt:element name="results">
      <xslt:for-each select="ns1:table">
        <xslt:for-each select="ns1:tr">
          <xslt:for-each select="ns1:td">
            <xslt:variable name="_value" select="normalize-space(.)"/>
            <xslt:element name="result">
              <xslt:element name="value">
                <xslt:value-of select="$_value"/>
              </xslt:element>
            </xslt:element>
          </xslt:for-each>
        </xslt:for-each>
      </xslt:for-each>
    </xslt:element>
  </xslt:template>
</xslt:stylesheet>

But the resulting output of the XSLT is just:

<results/>

I suspect it's a namespace issue but as far as I can tell the namespace is being handled correctly in the XSLT. The default namespace from the input XML is defined as "ns1" in the XSLT and used on every XPath expression in that XSLT. So I'm at a loss for what I'm missing.

EDIT 2014-02-09: Turned out to be a bug in the software platform I was using to run the XSLT. The XML snippet I pasted above is actually just a table from a larger document. To just grab the table I was calling an XPATH first, like this:

DECLARE myXML LONGVARCHAR;
DECLARE myOutXML XML;
SET outXml = XPATH(myOutXML, '//*[@id=''ctl07_tblMain'']');

Where 'outXml' was being fed into the XSLT. I had to change it to this to make it work:

SET myOutXML = CAST(XPATH(myOutXML, '//*[@id=''ctl07_tblMain'']') AS LONGVARCHAR);
SET outXml = myOutXML;

For some reason CASTing the result of the XPATH from XML to LONGVARCHAR and then returning it back as an XML fixed the problem.

Was it helpful?

Solution

For your surprise, I'm getting the output with your input XML and XSLT. Something like this:

<results>
<result>
    <value>Site Type</value>
</result>
<result>
    <value>Pet</value>
</result>
<result>
    <value>Electric</value>
</result>
.....

OTHER TIPS

This is not actually to do with namespaces, as it looks like they are all declared and referenced correctly.

However, I am surprised you are not actually getting an error when you run your XSLT, because you have two variable declarations for the same variable name in the template. Firstly...

<xslt:variable name="_value"/>

And later...

<xslt:variable name="_value" select="normalize-space(.)"/>

This is not actually allowed in the same template. In case you didn't realise, variables in XSLT are "immutable", meaning they can't be changed once defined. Moreover, you don't need to 'declare' them and 'initialise' them later on.

Read up about at http://www.w3.org/TR/1999/PR-xslt-19991008#local-variables where it says "It is an error if a binding established by an xsl:variable or xsl:param element within a template shadows another binding established by an xsl:variable or xsl:param element also within the template"

What I suspect is happening is that your XSLT processor is not informing you of the error, but simply not executing the block of code the error occurs in. Try removing the first variable declaration (which is actually setting _value to an empty string).

Having said that, you XSLT can be simplified somewhat. You don't need to nest all the xsl:for-each statements, but combine them into one

<xslt:for-each select="ns1:table/ns1:tr/ns1:td"/>

Or even this...

<xslt:for-each select=".//ns1:td"/>

Better still, use template matching!

<xslt:apply-templates select=".//ns1:td"/>

In fact, you don't really need to declare any variables at all here.Try this XSLT....

<xslt:stylesheet xmlns:xslt="http://www.w3.org/1999/XSL/Transform"  xmlns:csw-xform="http://www.compositesw.com/2003/xform" xmlns:ns1="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
  <xslt:template match="/">
    <xslt:element name="results">
      <xslt:apply-templates select=".//ns1:td"/>
    </xslt:element>
  </xslt:template>

  <xslt:template match="ns1:td">
      <xslt:element name="result">
      <xslt:element name="value">
        <xslt:value-of select="normalize-space(.)"/>
      </xslt:element>
    </xslt:element>
  </xslt:template>
</xslt:stylesheet>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top