RE: RE: [xsl] xsl:apply-templates with variable

Subject: RE: RE: [xsl] xsl:apply-templates with variable
From: cknell@xxxxxxxxxx
Date: Thu, 23 Sep 2004 13:01:42 -0400
It's best if we keep this thread on the list so that others might benefit from 
whatever solution may evolve. Please respond to the list.

I'm having touble understanding why the solution I offered is unsatisfactory.

The problem you have is that you wish to supply the name of a node as a 
parameter and use the value of that parameter to select a template match by 
dynamically evaluating the parameter in a select="" operation. As I said, the 
XSLT specification specifically prohibits this use, so you will have to find 
another way to do it.

I suggested using an xsl:choose structure to evaluate the string value of the 
passed parameter and select the appropriate template to call. You replied, "I 
will not have any idea about the value that is being passed to me."

If you knew precisely what the value of the parameter was before it was 
supplied, you would have no need for the parameter at all. You could simply 
hard-wire the transformation and be done with it. The only way that any value 
supplied by the parameter can be useful in this case is if matches the name of 
one of the elements (e.g., "CUSTOMER", "LAST_NAME", "DEPARTMENT"). Given that, 
you simply make one xsl:when element inside the xsl:choose for each element 
name that could be supplied. 

If you simply *must* do a dynamic evaluation, you will have to go to an 
extension function. The best set of these is probably EXSLT 
(http://www.exslt.org/dyn/index.html). Use of EXSLT and other extension 
functions varies with the XSL processor you are using. Since you are moving 
away from purse XSL, you have to be aware of the risk of non-portability in 
your application.

-- 
Charles Knell
cknell@xxxxxxxxxx - email



-----Original Message-----
From:     Paria Heidari <pheidari@xxxxxxxxxxxxxx>
Sent:     Thu, 23 Sep 2004 11:34:46 -0400
To:       <cknell@xxxxxxxxxx>
Subject:  RE: [xsl] xsl:apply-templates with variable

Hi Charles,
 
I am sorry that I am replying directly to you. But you were the only one
who responded to my post.
 
I will not have any idea about the value that is being passed to me. I
have tried so many things and back to the first place again
unsuccessful. 
 
I'll appreciate any ideas or suggestions you might have.
 
Regards,
Paria
 
 
 
------------------------------
 
Date: Tue, 21 Sep 2004 16:35:40 -0400
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
From: cknell@xxxxxxxxxx
Subject: RE: [xsl] xsl:apply-templates with variable
Message-ID: <B0029234920@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>
 
The last exception points you in the right direction.
 
"javax.xml.transform.TransformerException: A node test that matches
either NCName:* or QName was expected."
 
The spec specifically prohibits the kind of dynamic evaluation in
template matching and in XPath expressions. Michael Kay has answered
this kind of question many times on this list.
 
You might try a construct like this:
 
<xsl:choose>
  <xsl:when test="$ROOT='CUSTOMER'">
    <xsl:apply-templates select="CUSTOMER"/>
  </xsl:when>
  <xsl:when test="$ROOT='DEPARTMENT'">
    <xsl:apply-templates select="DEPARTMENT"/>
  </xsl:when>
  <xsl:otherwise>

  </xsl:otherwise>
</xsl:choose>
-- 
Charles Knell
cknell@xxxxxxxxxx - email
---------------------------------
 
 
Date: Tue, 21 Sep 2004 16:12:27 -0400
To: <xsl-list@xxxxxxxxxxxxxxxxxxxxxx>
From: "Paria Heidari" <pheidari@xxxxxxxxxxxxxx>
Subject: xsl:apply-templates with variable
Message-ID:
<8BB65B8A64970A44B5AAA23988DC4CD6CD3AA8@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
m>
 
Hello All,
 
I have the following XML file:
 
<CUSTOMERS>=09
      <CUSTOMER>
            <CUST_ID>2</CUST_ID>
            <FIRST_NAME>test</FIRST_NAME>
            <LAST_NAME>test2</LAST_NAME>  =09
            <CUST_ACCUCAST_DATA>
                  <CAD_CUST_ID>2</CAD_CUST_ID>
                  <MSG_CONTENT>T</MSG_CONTENT>
                  <BAD_EMAIL> </BAD_EMAIL>
                  <USER_AGENT>Mozilla/4.0</USER_AGENT>
                  <EMAIL_AGENT> </EMAIL_AGENT>
            </CUST_ACCUCAST_DATA>
            <DEPARTMENT>
                  <D_ID>2</D_ID>
                  <D_NAME>Sales</D_NAME>
            </DEPARTMENT>
            <ORDERSS>
                  <ORDERS>
                        <O_ID>2</O_ID>
                  </ORDERS>
            </ORDERSS>
      </CUSTOMER>
</CUSTOMERS>
 
---------------------
with following xslt:
 
<xsl:stylesheet version "1.0" 
            xmlns:xsl "http://www.w3.org/1999/XSL/Transform"; 
            xmlns:fo "http://www.w3.org/1999/XSL/Format";>
<xsl:param name "ROOT"/>
 
  <xsl:template match "CUSTOMERS">
    

=09  
  </xsl:template>
 
  <xsl:template match "CUSTOMER">
    <xsl:call-template name "printNode"/>
  </xsl:template>
 
  <xsl:template name "printHeaders">
    <tr bgcolor "#4D5D97">
      <xsl:variable name "spanA"
select "count(CUSTOMER[1]/child::*[count(child::*) 0])"/>
      <td colspan "{$spanA}">
      <xsl:text> </xsl:text>
      </td>
      <xsl:for-each select "CUSTOMER[1]/child::*[count(child::*) >
0]">
        <xsl:for-each select "child::*[1]">
        <xsl:variable name "spanB" select "count(child::*)"/>
        <td colspan "{$spanB}" valign "top">
          <font face "Arial" size "3" color "white">
            <b><xsl:value-of select "name()"/></b>
          </font>
        </td>
      </xsl:for-each>
      </xsl:for-each>
    </tr>
    <tr bgcolor "#4D5D97">
      <xsl:for-each  select "CUSTOMER[1]/child::*[count(child::*) 0]">
      <td valign "top">
        <font face "Arial" size "3" color "white">
          <b><xsl:value-of select "name()"/></b>
        </font>
      </td>
      </xsl:for-each>
      <xsl:for-each select "CUSTOMER[1]/child::*[count(child::*) >
0]">
        <xsl:for-each select "child::*[1]">
        <xsl:for-each select "child::*">
          <td valign "top">
            <font face "Arial" size "3" color "white">
            <b><xsl:value-of select "name()"/></b>
            </font>
          </td>
        </xsl:for-each>
      </xsl:for-each>
      </xsl:for-each>
    </tr>
  </xsl:template>
 
  <xsl:template name "printValues">
    <xsl:for-each select "child::*">
      <xsl:if test "count(child::*) 0">
      <td>
        <font face "Arial" size "3" color "black">
          <xsl:value-of select "."/>
         </font>
      </td>
      </xsl:if>
      <xsl:if test "count(child::*) > 0">
      <xsl:variable name "span" select "count(descendant::*)-1"/>
      <td colspan "{$span}" valign "top">
        <table cellpadding "5" cellspacing "2" border "0"
width "100%">
          <xsl:for-each select "child::*">
            <tr>  
            <xsl:if test "count(child::*)   0">
              <td><xsl:text> </xsl:text></td>
            </xsl:if>
            <xsl:for-each select "child::*">
              <td>
                <font face "Arial" size "3" color "black">
                  <xsl:value-of select "."/>
                 </font>
              </td>
            </xsl:for-each>
            </tr>
          </xsl:for-each>
        </table>
      </td>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>
 
  <xsl:template name "printNode">
    <tr bgcolor "#FFFFFF">  
      <xsl:if test "position() mod 2   0">
      <xsl:attribute name "bgcolor">#E7ECF0</xsl:attribute>
      </xsl:if>
      <xsl:call-template name "printValues"/>
    </tr>
  </xsl:template>
  
</xsl:stylesheet>
 
-------------------
 
I have added the <xsl:param name "ROOT"/> and passing in this value  from
my Java code.  This value will be a dynamic variable in my xml file. For
now I am passing in CUSTOMER as the value. I print my $ROOT to make sure
I have passed in the correct value. 
 
When I replace 'CUSTOMER' with ($ROOT) within my xslt file I get the
following error:
 
avax.xml.transform.TransformerConfigurationException:
javax.xml.transform.TransformerConfigurationException:
javax.xml.transform.TransformerException:
javax.xml.transform.TransformerException: A node test that matches
either NCName:* or QName was expected.
 
---------------------
This is my xslt file after I replace the 'CUSTOMER' with ($ROOT)
<xsl:stylesheet version "1.0" 
            xmlns:xsl "http://www.w3.org/1999/XSL/Transform"; 
            xmlns:fo "http://www.w3.org/1999/XSL/Format";>
<xsl:param name "ROOT">CUSTOMER</xsl:param>
 
  <xsl:template match "CUSTOMERS">
    

=09  
  </xsl:template>
 
  <xsl:template match "$ROOT">
    <xsl:call-template name "printNode"/>
  </xsl:template>
 
  <xsl:template name "printHeaders">
    <tr bgcolor "#4D5D97">
      <xsl:variable name "spanA"
select "count(($ROOT)[1]/child::*[count(child::*) 0])"/>
      <td colspan "{$spanA}">
      <xsl:text> </xsl:text>
      </td>
      <xsl:for-each select "($ROOT)[1]/child::*[count(child::*) >
0]">
        <xsl:for-each select "child::*[1]">
        <xsl:variable name "spanB" select "count(child::*)"/>
        <td colspan "{$spanB}" valign "top">
          <font face "Arial" size "3" color "white">
            <b><xsl:value-of select "name()"/></b>
          </font>
        </td>
      </xsl:for-each>
      </xsl:for-each>
    </tr>
    <tr bgcolor "#4D5D97">
      <xsl:for-each select "($ROOT)[1]/child::*[count(child::*) 0]">
      <td valign "top">
        <font face "Arial" size "3" color "white">
          <b><xsl:value-of select "name()"/></b>
        </font>
      </td>
      </xsl:for-each>
      <xsl:for-each select "($ROOT)[1]/child::*[count(child::*) >
0]">
        <xsl:for-each select "child::*[1]">
        <xsl:for-each select "child::*">
          <td valign "top">
            <font face "Arial" size "3" color "white">
            <b><xsl:value-of select "name()"/></b>
            </font>
          </td>
        </xsl:for-each>
      </xsl:for-each>
      </xsl:for-each>
    </tr>
  </xsl:template>
 
  <xsl:template name "printValues">
    <xsl:for-each select "child::*">
      <xsl:if test "count(child::*) 0">
      <td>
        <font face "Arial" size "3" color "black">
          <xsl:value-of select "."/>
         </font>
      </td>
      </xsl:if>
      <xsl:if test "count(child::*) > 0">
      <xsl:variable name "span" select "count(descendant::*)-1"/>
      <td colspan "{$span}" valign "top">
        <table cellpadding "5" cellspacing "2" border "0"
width "100%">
          <xsl:for-each select "child::*">
            <tr>  
            <xsl:if test "count(child::*)   0">
              <td><xsl:text> </xsl:text></td>
            </xsl:if>
            <xsl:for-each select "child::*">
              <td>
                <font face "Arial" size "3" color "black">
                  <xsl:value-of select "."/>
                 </font>
              </td>
            </xsl:for-each>
            </tr>
          </xsl:for-each>
        </table>
      </td>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>
 
  <xsl:template name "printNode">
    <tr bgcolor "#FFFFFF">  
      <xsl:if test "position() mod 2   0">
      <xsl:attribute name "bgcolor">#E7ECF0</xsl:attribute>
      </xsl:if>
      <xsl:call-template name "printValues"/>
    </tr>
  </xsl:template>
  
</xsl:stylesheet>
 
I'll appreciate any help or ideas.
 
Many thanks in advance,
Paria



-- 
Charles Knell
cknell@xxxxxxxxxx - email

--+------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe@xxxxxxxxxxxxxxxxxxxxxx>
--+--

Current Thread