Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old March 26th, 2007, 08:14 AM
Tre Tre is offline
Authorized User
 
Join Date: Mar 2007
Posts: 15
Thanks: 0
Thanked 0 Times in 0 Posts
Default Param Question

I have a question about Params in XSLT. I need to incement a variable (or param) in one of my templates. I can't call the template that I am using recursively becuase is has SVG embedded within it to draw a chart.

Is it possible to call another template and pass a param to be incremented and then pass that param back?

Or can I put another template within the chart template to increment the param.

Or are there any other ways of going about doing this?

Thanks in advance.

Trevor.
 
Old March 26th, 2007, 08:23 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

You say you need to increment a variable or param, but many such problems can be solved using the position() function which is in effect self-incrementing.

You say:

>I can't call the template that I am using recursively becuase is has SVG embedded within it to draw a chart.

But that looks like a non-sequitur. I can't see any reason why the fact that your template has SVG embedded within it should stop you calling it recursively.

If you can't use position(), you need to use recursion.

Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
 
Old March 26th, 2007, 08:49 AM
Tre Tre is offline
Authorized User
 
Join Date: Mar 2007
Posts: 15
Thanks: 0
Thanked 0 Times in 0 Posts
Default

I can't use the position() function because I have a set of customer inestments within my xml document. Each customer has more than one investment but each customer has a unique ID. For each customer I need to loop through all the records that contain the same customer ID and draw a new "bar" in my bar chart for each investment that customer has.

I want to start drawing the bar chart from the left hand side of the screen so if I use the position function the bar chart starts to get rendered off the screen on the right hand side by the time we are on the third customer.

I basically need to reset the "position counter" for each new customer and increment it until there are no more records left for that customer. Then reset the counter and start again for the next customer etc etc...

I can't see how to use recursion in this case as the SVG graphic wont render properly as far as I can see.

Below is my current Bar Chart template with position() being used as the counter.


  <xsl:template name="barChart">
    <fo:instream-foreign-object>
      <svg width="400px" height="560px" xmlns="http://www.w3.org/2000/svg">
        <text x="40" y="25"
            style="font-family:Times New Roman; font-size: 10; fill: #0099ff; stroke: black; stroke-width: 1">
          Position Summary Histogram
        </text>
        <g id="BarChart" transform="translate(0,150) scale(1)" x="0" y="400">

          <xsl:for-each select="$source">
            <xsl:if test="number(PortfolioID) = $currentSecurity -1">
              <xsl:variable name="val" select="Quantity"/>
              <rect x="{position()*25}" y="-{$val div 10}" height="{$val div 10}" width="15" stroke = "wheat" fill = "cornflowerblue"/>
              <text x="{position()*25 + 7.5}" y="0" rotate="50" style="font-family:arial;text-anchor:middle;baseline-shift:-15;$pagePosition = $pagePosition+1">
                  <xsl:value-of select="./SecurityID"/>
              </text>
            </xsl:if>

          </xsl:for-each>
        </g>
      </svg>
  </fo:instream-foreign-object>
    <block break-before="page"/>
  </xsl:template>


Below is an example of my XML

<NewDataSet>
  <Security>
    <PortfolioID>1</PortfolioID>
    <Quantity>183.84</Quantity>
    <FirstName>James</FirstName>
    <LastName>Carter</LastName>
    <Description>Stone Money Market</Description>
    <SecurityID>20</SecurityID>
  </Security>
  <Security>
    <PortfolioID>1</PortfolioID>
    <Quantity>623.08</Quantity>
    <FirstName>James</FirstName>
    <LastName>Carter</LastName>
    <Description>Vantage Bond Index Fund</Description>
    <SecurityID>24</SecurityID>
  </Security>
  <Security>
    <PortfolioID>1</PortfolioID>
    <Quantity>605.358</Quantity>
    <FirstName>James</FirstName>
    <LastName>Carter</LastName>
    <Description>Pimco Total Return Fund</Description>
    <SecurityID>25</SecurityID>
  </Security>
  <Security>
    <PortfolioID>1</PortfolioID>
    <Quantity>454.295</Quantity>
    <FirstName>James</FirstName>
    <LastName>Carter</LastName>
    <Description>Montgomery Equity Income</Description>
    <SecurityID>26</SecurityID>
  </Security>
  <Security>
    <PortfolioID>2</PortfolioID>
    <Quantity>1147.6</Quantity>
    <FirstName>Kathleen</FirstName>
    <LastName>Carter</LastName>
    <Description>Stone Money Market</Description>
    <SecurityID>20</SecurityID>
  </Security>
  <Security>
    <PortfolioID>2</PortfolioID>
    <Quantity>706.667</Quantity>
    <FirstName>Kathleen</FirstName>
    <LastName>Carter</LastName>
    <Description>Pimco Total Return Fund</Description>
    <SecurityID>25</SecurityID>
  </Security>

 
Old March 26th, 2007, 09:22 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

>I basically need to reset the "position counter" for each new customer and increment it until there are no more records left for that customer. Then reset the counter and start again for the next customer etc etc...

No, that's what you would need to do if you were using a procedural programming language. You can't use the same kind of thinking in a functional programming language: and usually you don't need to. You're instinctively thinking about the problem algorithmically rather than functionally.

You first need to group securities by customer: in XSLT 2.0 use xsl:for-each-group, in 1.0 use Muenchian grouping (www.jenitennison.com/xslt/grouping). Then you need to iterate over the resulting customers. In this grouped iteration position() will give you the current customer number and can be used to compute the x coordinate in your graphic.

Schematically, in XSLT 2.0:

<xsl:for-each-group select="Security" group-by="PortfolioID">
  <xsl:variable name="x" select="position()*0.25"/>
  <xsl:for-each select="current-group()">
     -- draw a rectangle --




Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
 
Old March 27th, 2007, 08:06 AM
Tre Tre is offline
Authorized User
 
Join Date: Mar 2007
Posts: 15
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Unfortunately I dont have XSLT V2.0 so I am trying to use the Muenchian grouping method as you suggested.

Below is my key and template:

  <xsl:key name="portfolios" match="NewDataSet/Security" use="number(.//PortfolioID)"/>

  <xsl:template match="NewDataSet/Security" name="Tester">
    <xsl:for-each select="Security[count(. | key('portfolios', number(.//PortfolioID))[1]) = 1]">
      <xsl:sort select="number(.//PortfolioID)" />
      <xsl:for-each select="key('portfolios', number(.//PortfolioID))">
        <xsl:sort select="forename" />
        <xsl:value-of select="position()"/>
        <xsl:value-of select=".//FirstName" />
        <xsl:value-of select=".//LastName" />
      </xsl:for-each>
    </xsl:for-each>
  </xsl:template>



I am just trying to get this basic template working before I make it more complex. Currently, when I run it nothing happens at all. I want it to group all the records by "PortfolioID" and then display the position and names of all records.

Using this method, will positio() reset itself for each new group that has been created?
 
Old March 27th, 2007, 08:34 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

<xsl:template match="NewDataSet/Security" name="Tester">
    <xsl:for-each select="Security[...]"

Your Security element does not have any children called Security.

You want

<xsl:template match="NewDataSet">

I think.

<xsl:sort select="forename" />

I don't see an element called forename.



Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
 
Old March 27th, 2007, 08:51 AM
Tre Tre is offline
Authorized User
 
Join Date: Mar 2007
Posts: 15
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Thank you very much, that works great now and I can use the position() function as a counter for each group as well!

It's iteresting to note though that it wont work at all if I call the template by name. But if I call <xsl:apply-templates/> then it works fine. Why might that be?

Thanks again for your excellent help, I appreciate it a great deal.

 
Old March 27th, 2007, 09:13 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

>It's iteresting to note though that it wont work at all if I call the template by name. But if I call <xsl:apply-templates/> then it works fine.

position() is the position of the current node in the current iteration: apply-templates and for-each establish a current iteration, as do "/" and "[]".


Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference





Similar Threads
Thread Thread Starter Forum Replies Last Post
document() and param - help please akentanaka XSLT 2 July 5th, 2008 06:35 AM
question on with-param anboss XSLT 6 June 23rd, 2008 05:58 PM
Reassign param value? victorcorey XSLT 2 November 29th, 2007 05:33 AM
with-param nodeset RoeZ XSLT 6 November 1st, 2007 06:53 PM
passing param to XSLT Dangerous Dave XSLT 0 April 30th, 2004 07:46 PM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.