Gobbledigook
Gobbledigook

Reputation: 472

XSL Dynamic Node Reference

I'm quite new to XSL, and I'm trying to dynamically reference nodes from an XML file using a template.

To give a bit more information, I'm using Cast Iron to generate the initial XML, and it returns multiple Result Sets, some of them with multiple rows. A Sample XML is as follows:

<resultSets>
    <resultSet/>
    <resultSet>
      <row>
        <column1>1</column1>
        <column2>Hello</column2>
      </row>
    </resultSet>
    <resultSet>
      <row>
        <column1/>
      </row>
      <row>
        <column1/>
      </row>
    </resultSet>
</resultSets>

So I'm trying to transform this into something that can be used by the customer. I thought of using a template with a few inputs to make my life easier.

I wanted to design the template that by entering a number for the result set, a number for the row, and the name of the column, it would reference the data. The problem is, when I reference it, the resulting node doesn't get created. So my question is: How do I reference a Param as an Xml Node?

Here is what I have for the template:

<xsl:template name="getData">
    <xsl:param name="resultset" select="0" />
    <xsl:param name="position" select="0" />
    <xsl:param name="column-name" select="''" />
    <!-- Checking to see if Parameters were passed in.  This seems to work correctly -->
    <xsl:if test="($resultset &gt; 0)and($position &gt; 0)and($column-name != '')">
        <!-- Check to see if there are any rows in the resultSet.  This seems to work correctly -->
        <xsl:if test="count(//resultSets/resultSet[position() = $resultset]/row[position() = $position]) &gt; 0">
            <!-- This part fails; nothing is referenced --> 
            <xsl:value-of select="//resultSets/resultSet[position() = $resultset]/row[position() = $position][@name = $column-name]"/>
        </xsl:if>
    </xsl:if>
</xsl:template>

Here is how I'm trying to reference it (as an example): This should return 'Hello' from the XML file (shouldn't it?)

<xsl:element name="SampleElement">
 <xsl:call-template name="getData">
  <xsl:with-param name="resultset" select="2" />
  <xsl:with-param name="position" select="1" /> 
  <xsl:with-param name="column-name" select="'column2'" />
 </xsl:call-template>
</xsl:element>

Sorry if my question is unclear or has been asked before, I didn't find anything.

Upvotes: 1

Views: 637

Answers (1)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243459

Simply use:

<xsl:value-of select=
  "/*/resultSet[position()=$resultset]
        /row[position()=$position]
          /*[name()=$column-name]"/>

Do note that indexing in XPath is 1-based -- not 0-based.

Complete transformation:

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

  <xsl:param name="pResSetNo" select="2"/>
  <xsl:param name="pRowNo" select="1"/>
  <xsl:param name="pColName" select="'column2'"/>


    <xsl:template match="/">
      <xsl:copy-of select=
      "/*/resultSet[position()=$pResSetNo]
        /row[position()=$pRowNo]
          /*[name()=$pColName]"/>
    </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<resultSets>
    <resultSet/>
    <resultSet>
      <row>
        <column1>1</column1>
        <column2>Hello</column2>
      </row>
    </resultSet>
    <resultSet>
      <row>
        <column1/>
      </row>
      <row>
        <column1/>
      </row>
    </resultSet>
</resultSets>

the wanted, correct result is produced:

Hello

Upvotes: 1

Related Questions