RE: [xsl] How to use an attribute value passed as a param to a na med template for pattern matching

Subject: RE: [xsl] How to use an attribute value passed as a param to a na med template for pattern matching
From: Nate Austin <naustin@xxxxxxxxxx>
Date: Mon, 12 Mar 2001 16:15:39 -0600
Neal-

I did a couple of things.  For starters, I changed a couple of your
xsl:for-each statements to be xsl:apply-templates instead.  This is
generally considered to be better form (no need to reopen a debate on this
topic :) ).  Second, in your xsl:call-template to 'twoparam' I changed the
p_attr attribute to be a string (put single quotes around it).  Otherwise,
it would be trying to select all 'a' nodes that were children of the current
node.  Then for the totalling piece, I wasn't sure which you wanted to do:
sum(typea * typeb) ie. the multiply each the 'Value' of each 'Try2' node
together and sum up all of the results, or sum all Try2 type a and multiply
by sum of all Try2 type b.  The latter is commented out and is much easier
to do.  The former uses a recursively called template.  This solution works,
although I'm not sure it'll be your best solution.  I'm sure some guru can
shoot back some fabulous xpath or more efficient solution using an extension
function or something.  The reason your summation code returned an error is
because multiplication returns a number, and the sum function is expecting a
node-set.  I hope this helps!

-Nate

Stylesheet follows:

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

  <xsl:template match="/">
    <Output>
      <xsl:apply-templates select="//Top/Repeater"/>
      <Totals>
        <Total_1>
          <xsl:value-of select="sum(//Try2[@type='b']/Value)"/>
        </Total_1>
        <Total_2x3>
          <!--  Following commented out because it gives this error:
             XSLT Error (javax.xml.transform.TransformerException): Can not
             convert #NUMBER to a NodeList!
            <xsl:value-of select="sum(//Try2[@type='a']/Value *
//Try2[@type='b']/Value)"/>
          -->
          <!-- <xsl:value-of
               select="sum(//Try2[@type='a']/Value) *
sum(//Try2[@type='b']/Value)"/>
           -->
           <xsl:call-template name="Try2-recurse">
             <xsl:with-param name="try2-list" select="//Try2"/>
             <xsl:with-param name="total" select="0"/>
           </xsl:call-template>
        </Total_2x3>
      </Totals>
    </Output>
  </xsl:template>

  <xsl:template match="Repeater">
    <Group>
      <Note>hello</Note>
      <Catch1>
        <xsl:call-template name="oneparam">
          <xsl:with-param name="p_node">Try1</xsl:with-param>
        </xsl:call-template>
      </Catch1>
      <Catch2>
        <xsl:call-template name="twoparam">
          <xsl:with-param name="p_node">Try2</xsl:with-param>
          <xsl:with-param name="p_attr" select="'a'"/>  <!-- must have '' to
denote a string -->
        </xsl:call-template>
      </Catch2>
      <xsl:apply-templates select="Try2[@type='b']"/>
    </Group>
  </xsl:template>

  <xsl:template match="Try2">
    <Catch3>
      <xsl:call-template name="simple"/>
    </Catch3>
  </xsl:template>

<!-- ========== named templates follow ========== -->
  <xsl:template name="Try2-recurse">
    <xsl:param name="try2-list"/>
    <xsl:param name="total"/>
    <xsl:choose>
      <xsl:when test="count($try2-list) &gt; 0">
        <xsl:call-template name="Try2-recurse">
          <xsl:with-param name="try2-list" select="$try2-list[position()
&gt; 2]"/>
          <xsl:with-param name="total" select="$total + ($try2-list[1]/Value
* $try2-list[2]/Value)"/>
        <!-- Assumption:  Every type='a' has exactly one type='b' that is a
                          following-sibling and not null string
          -->
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$total"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="oneparam">
    <xsl:param name="p_node">.</xsl:param>
    <xsl:value-of select="*[name()=$p_node]/Value"/>
  </xsl:template>

  <xsl:template name="twoparam">
    <xsl:param name="p_node">.</xsl:param>
    <xsl:param name="p_attr"></xsl:param>
    <xsl:value-of select="*[name()=$p_node][(@type=$p_attr)]/Value"/>
  </xsl:template>

  <xsl:template name="simple">
    <xsl:value-of select="./Value"/>
  </xsl:template>
 
 </xsl:stylesheet>

>Date: Sun, 11 Mar 2001 22:08:52 -0500
>From: "Neal Mulvenna" <mulvenna@xxxxxxxxxx>
>Subject: [xsl] How to use an attribute value passed as a param to a named
template
>for pattern matching
>
>Hi, this is my first post to this newly discovered usergroup.  I am
>experimenting with using XSLT in an integration environment for XML-XML
>transforms. More about that in future posts.  right now I'm trying to find
>out how to use named templates with pattern matching info passed to them as
>params.  The example included shows three different named templates:
>- -  "oneparam" template (param = element to be matched) works fine,
although
>I am not sure why.  I found the solution in the FAQ, but would like to
>understand why it works and why the 'intuitively obvious' way doesn't.
>Suggested reading please.
>- - "twoparam" template doesn't work.  This is just one of many that I've
>tried, all fail.  What is the trick for handling the attribute value
>properly?
>- - "simple" template works fine, the pattern matching was first done in
the
>main template.  But the only way I know of to properly position prior to
>the named template call is to do a for-each block, even if I know there is
>just a single occurence.  Is this inefficient?
>
>And, while I'm at it, what is wrong with my single total line sum( a * b)
>statement in the example (commented out because of the error it generates)?
>I tried a couple things from the Math examples in the FAQ, no luck.
>
>I am using Lotus xsl 2.0.0 (xalan) from the IBM alphaworks site
>Thanks in advance for any insight you may provide.  On to the example:
>First the input XML, NealExample.xml:
><!-- NealExample.xml -->
><Top>
>  <Repeater index="1">
>    <Try1>
>      <Value>1</Value>
>    </Try1>
>    <Try2 type="a">
>      <Value>2</Value>
>    </Try2>
>    <Try2 type="b">
>      <Value>3</Value>
>    </Try2>
>  </Repeater>
>  <Repeater index="2">
>    <Try1>
>      <Value>11</Value>
>    </Try1>
>    <Try2 type="a">
>      <Value>12</Value>
>    </Try2>
>    <Try2 type="b">
>      <Value>3.1</Value>
>    </Try2>
>  </Repeater>
></Top>
>
>Now the xsl, NealExample.xsl
><xsl:stylesheet version="1.0" xmlns:xsl
>="http://www.w3.org/1999/XSL/Transform";>
><!--
>========================================================================
>     NealExample.xsl
>  ========================================================================
>- -->
><xsl:template match="/">
><Output>
><xsl:for-each select="//Repeater">
>  <Group>
>    <Note><xsl:text>hello</xsl:text></Note>
>    <Catch1>
>      <xsl:call-template name="oneparam">
>        <xsl:with-param name="p_node">Try1</xsl:with-param>
>      </xsl:call-template>
>    </Catch1>
>    <Catch2>
>      <xsl:call-template name="twoparam">
>        <xsl:with-param name="p_node">Try2</xsl:with-param>
><!--        <xsl:with-param name="p_attr">a</xsl:with-param> -->
>        <xsl:with-param name="p_attr" select="a"/>
>      </xsl:call-template>
>    </Catch2>
>  <xsl:for-each select="Try2[@type='b']">
>    <Catch3>
>      <xsl:call-template name="simple"/>
>    </Catch3>
>  </xsl:for-each>
></Group>
></xsl:for-each>
><Totals>
>  <Total_1>
>    <xsl:value-of select="sum(//Try2[@type='b']/Value)"/>
>  </Total_1>
>  <Total_2x3>
>    <!--  Following commented out because it gives this error:
>      XSLT Error (javax.xml.transform.TransformerException): Can not
>convert #NUMBER to a NodeList!
>
>    <xsl:value-of select="sum(//Try2[@type='a']/Value *
//Try2[@type='b']/Value)"/>
>
>    end of comment-out -->
>  </Total_2x3>
></Totals>
></Output>
></xsl:template>
>
><!-- ========== named templates follow ========== -->
><xsl:template name="oneparam">
>  <xsl:param name="p_node">.</xsl:param>
>       <xsl:value-of select="*[name()=$p_node]/Value"/>
></xsl:template>
>
><xsl:template name="twoparam">
>  <xsl:param name="p_node">.</xsl:param>
>  <xsl:param name="p_attr"></xsl:param>
>       <xsl:value-of select="*[name()=$p_node][(@type=$p_attr)]/Value"/>
></xsl:template>
>
><xsl:template name="simple">
>       <xsl:value-of select="./Value"/>
></xsl:template>
></xsl:stylesheet>
>
>And this is the generated output XML:
><?xml version="1.0" encoding="UTF-8"?>
><Output>
> <Group>
>  <Note>hello</Note>
>  <Catch1>1</Catch1>
>  <Catch2/>
>  <Catch3>3</Catch3>
> </Group>
> <Group>
>  <Note>hello</Note>
>  <Catch1>11</Catch1>
>  <Catch2/>
>  <Catch3>3.1</Catch3>
> </Group>
> <Totals>
>  <Total_1>6.1</Total_1>
>  <Total_2x3/>
> </Totals>
></Output>
>
>Neal Mulvenna, IBM  Application Integration and Middleware Services and
Solutions
>Internet: mulvenna@xxxxxxxxxx

 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread