|
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
|
|
|
March 21st, 2008, 11:54 AM
|
Authorized User
|
|
Join Date: Jan 2007
Posts: 39
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
looping through static array
im trying to loop through a static array of variables, passing each variable to the same template. i have the following block of XSLT that id like to call repeatedly as a new template:
Code:
<xsl:if test="Collection/Hits/Content[Html/root/Specialty='Anesthesiology']">
<xsl:call-template name="specialtyHeader">
<xsl:with-param name="specialtyHeader">Anesthesiology</xsl:with-param>
</xsl:call-template>
<xsl:for-each select="Collection/Hits/Content[Html/root/Specialty='Anesthesiology']">
<xsl:sort select="Html/root/SVRMCPhysician" order="descending" />
<xsl:sort select="Html/root/LastName" order="ascending" />
<xsl:call-template name="display"></xsl:call-template>
</xsl:for-each>
</xsl:if>
[u]im trying to accomplish something like:</u>
some-variable = array('Anesthesiology','Behavioral Health','Cancer Center')
for-each (some-variable)
{
call my block of XSLT above as a template
}
is this possible with XSLT?
cheers,
steve
|
March 21st, 2008, 12:28 PM
|
Friend of Wrox
|
|
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
|
|
Well with XSLT/XPath 2.0 you can form a sequence of atomic values e.g. strings
Code:
<xsl:variable name="some-variable" as="xs:string*"
select="('Anesthesiology','Behavioral Health','Cancer Center')"/>
<xsl:for-each select="$some-variable">
I am not sure however whether calling the other code block as a template makes sense as there you have XPath expresssion like Collection/Hits/Content[Html/root/Specialty='Anesthesiology'] accessing the child 'Collection' of the context node and with the sequence formed above there won't be a context node having any children.
Microsoft MVP - XML
|
March 21st, 2008, 12:33 PM
|
Authorized User
|
|
Join Date: Jan 2007
Posts: 39
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
thanks for the reply Martin.
unfortunately im stuck with using XSLT/XPath 1.0 here. does anyone know of a possible solution for 1.0?
thanks!
steve
|
March 21st, 2008, 12:39 PM
|
Friend of Wrox
|
|
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
|
|
With XSLT 1.0 you need to put the values into some node-set you can access, one way is to have an additional XML input document with e.g.
Code:
<list>
<item>Anesthesiology</item>
<item>Behavioral Health</item>
<item>Cancer Center</item>
</list>
and process document('list.xml')/list/item.
Another way is to put the data into your stylesheet e.g.
Code:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:dt="http://example.com/2008/data">
<dt:data>
<list>
<item>Anesthesiology</item>
<item>Behavioral Health</item>
<item>Cancer Center</item>
</list>
</dt:data>
<xsl:template match="/">
<xsl:for-each select="document('')/xsl:stylesheet/dt:data/list/item">
Microsoft MVP - XML
|
March 21st, 2008, 12:46 PM
|
Authorized User
|
|
Join Date: Jan 2007
Posts: 39
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
that's great Martin! your second solution of putting the data in my stylesheet works perfect!
gratefully yours,
steve
|
March 21st, 2008, 12:54 PM
|
|
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
There's no such thing as a "static array of variables" in XSLT, or for that matter in any other language I know of.
In XSLT 2.0 you can have a variable whose value is a sequence of strings:
<xsl:variable name="s" as="xs:string*"
select="('Anest', 'Behav', 'Cancer')"/>
and you can iterate over these strings:
<xsl:for-each select="$s">...</xsl:for-each>
If you're stuck with XSLT 1.0 then it's best to create an XML document with these values as elements, then you can iterate over the values using a path expression in the normal way.
Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
|
March 21st, 2008, 01:04 PM
|
Authorized User
|
|
Join Date: Jan 2007
Posts: 39
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
as you might have mentioned martin (although i have to admit i didn't fully understand the terminology you used cause im a relative n00b), this solution doesn't work:
Code:
<xsl:for-each select="document('')/xsl:stylesheet/dt:data/list/item">
<xsl:call-template name="specialtyHeader">
<xsl:with-param name="specialtyHeader"><xsl:value-of select="." /></xsl:with-param>
</xsl:call-template>
<xsl:for-each select="Collection/Hits/Content[Html/root/Specialty = .]">
<xsl:sort select="Html/root/SVRMCPhysician" order="descending" />
<xsl:sort select="Html/root/LastName" order="ascending" />
<xsl:call-template name="display"></xsl:call-template>
</xsl:for-each>
</xsl:for-each>
is there something i can do to make this solution work?
thanks,
steve
|
March 21st, 2008, 01:16 PM
|
Friend of Wrox
|
|
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
|
|
Within your xsl:for-each the context node is an 'item' element in the stylesheet. The inner xsl:for-each then attempts the process Collection/Hits/Content[Html/root/Specialty = .] but 'item' elements do not have 'Collection' child elements. I guess you probably want to use
Code:
<xsl:for-each select="document('')/xsl:stylesheet/dt:data/list/item">
<xsl:call-template name="specialtyHeader">
<xsl:with-param name="specialtyHeader"><xsl:value-of select="." /></xsl:with-param>
</xsl:call-template>
</xsl:for-each>
<xsl:for-each select="Collection/Hits/Content[Html/root/Specialty = .]">
<xsl:sort select="Html/root/SVRMCPhysician" order="descending" />
<xsl:sort select="Html/root/LastName" order="ascending" />
<xsl:call-template name="display"></xsl:call-template>
</xsl:for-each>
or you need to store the main root node e.g.
Code:
<xsl:variable name="main-root" select="/"/>
<xsl:for-each select="document('')/xsl:stylesheet/dt:data/list/item">
<xsl:call-template name="specialtyHeader">
<xsl:with-param name="specialtyHeader"><xsl:value-of select="." /></xsl:with-param>
</xsl:call-template>
<xsl:for-each select="$main-root/Collection/Hits/Content[Html/root/Specialty = .]">
<xsl:sort select="Html/root/SVRMCPhysician" order="descending" />
<xsl:sort select="Html/root/LastName" order="ascending" />
<xsl:call-template name="display"></xsl:call-template>
</xsl:for-each>
</xsl:for-each>
Microsoft MVP - XML
|
March 21st, 2008, 01:18 PM
|
|
Wrox Author
|
|
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
|
|
You need to understand which constructs are changing the context node. The outer xsl:for-each sets the context node to an item element, so the relative path expression Collection/Hits/Content starts from the wrong place. Similarly, inside the predicate [Html/root/Specialty = .], "." is a Content element.
To solve this, use variables. Set a variable outside the outer for-each
<xsl:variable name="x" select="."/>
and use it to anchor the inner for-each:
<xsl:for-each select="$x/Collection/...
In the predicate, you could use another variable, or you could use current().
Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
|
March 21st, 2008, 01:30 PM
|
Authorized User
|
|
Join Date: Jan 2007
Posts: 39
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Michael and Martin - you guys are great!
[u]i got it to work with the following:</u>
Code:
<xsl:variable name="main-root" select="/" />
<xsl:for-each select="document('')/xsl:stylesheet/dt:data/list/item">
<xsl:variable name="currentSpecialty" select="." />
<xsl:if test="$main-root/Collection/Hits/Content[Html/root/Specialty = $currentSpecialty]">
<xsl:call-template name="specialtyHeader">
<xsl:with-param name="specialtyHeader"><xsl:value-of select="$currentSpecialty" /></xsl:with-param>
</xsl:call-template>
<xsl:for-each select="$main-root/Collection/Hits/Content[Html/root/Specialty = $currentSpecialty]">
<xsl:sort select="Html/root/SVRMCPhysician" order="descending" />
<xsl:sort select="Html/root/LastName" order="ascending" />
<xsl:call-template name="display"></xsl:call-template>
</xsl:for-each>
</xsl:if>
</xsl:for-each>
cheers!
steve
|
|
|