Subject: Re: [xsl] Problem using recursive apply-templates calls From: George Cristian Bina <george@xxxxxxxxxxxxx> Date: Mon, 18 Sep 2006 14:51:47 +0300 |
Best Regards, George --------------------------------------------------------------------- George Cristian Bina <oXygen/> XML Editor, Schema Editor and XSLT Editor/Debugger http://www.oxygenxml.com
Thanks very much for your helpful reply George (sorry I wasn't able to
review it sooner). Unfortunately this was a situation in which I may have
simplified the XSL too much for the purposes of sending this to the list.
There are actually at least different kinds of performer roles that need to
be handled: Moderator, Speaker, Speaker-Featured, Performer,
Performer-Featured, Panelist/Discussant, a role filled in by the user, and
then hopefully also a performer with no role (but we can live without that
if we can't do it). Each Event or Performer Group may have one or more of
these Performers of each type.
The XSL you provide below which assumes all groups have one or more Moderators and that all the rest of the Performers are "Speakers" won't work for us. I've been playing with the code you gave me a bit, but am not sure this structure will work for what we want to do. We also wanted to list all the roles together if there is more than one of them for each event or each group. So the role name should be singular or plural depending on how many of each there are. Here is an example (an event probably would never actually look like this but this is what we want to handle):
Performer-Featured: Joe Blow Performers: Mike Smith, Alex Keaton Performer Group: Group #1 Moderator: George Bina Speakers: Allison Bloodworth, John Doe Performer: Jane Doe Panelist/Discussant: Fred Rogers Gymnast: Mike Jones
Is this hopelessly complicated? I'm sure it's because I don't entirely have
a grasp on how to walk the node tree, but I'm still not sure why as you say
below: -------------------------------
<xsl:apply-templates select="../../Performers"/>
will cause the <xsl:template match="Performers"> to be matched exactly in the same context as it was matched initially when you called
<xsl:apply-templates select="Performers"> <xsl:with-param name="performerLevels" select="2"/> </xsl:apply-templates>
This causes an infinite loop. ------------------------------- I can write some messy code that basically duplicates the performer template (and gives it a different name) for the performers inside groups, but hoped recursion would make that unnecessary. Any further ideas are very welcome!
Thanks! Allison
-----Original Message-----
From: George Cristian Bina [mailto:george@xxxxxxxxxxxxx] Sent: Tuesday, September 12, 2006 1:49 AM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: [xsl] Problem using recursive apply-templates calls
Hi Allison,
Your
<xsl:apply-templates select="../../Performers"/>
will cause the <xsl:template match="Performers"> to be matched exactly in the same context as it was matched initially when you called
<xsl:apply-templates select="Performers"> <xsl:with-param name="performerLevels" select="2"/> </xsl:apply-templates>
This causes an infinite loop.
A possible solution is to iterate first the individual speakers and print their information, then all the group performers and print group info. If you define two keys to match moderators and speakers for each group then you can just iterate on moderators and print their info and on speakers and print their info for each group. You can find below such a stylesheet, hope that helps.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="moderators" match="Performer[PerformerTypes/PerformerType[.='Moderator']]"
use="PerformerParentID"/>
<xsl:key name="speakers" match="Performer[PerformerTypes/PerformerType[.='Speaker']]"
use="PerformerParentID"/>
<xsl:template match="/">
<!-- Determine which TIMEFRAME to render -->
<html>
<body> Here are the events: <xsl:choose>
<xsl:when test="/Events/View/Timeframe='event'">
<xsl:call-template name="TimeframeEvent"/>
</xsl:when>
<xsl:when test="/Events/View/Timeframe='day'"> Do nothing </xsl:when>
</xsl:choose>
</body>
</html>
</xsl:template>
<xsl:template name="TimeframeEvent">
<xsl:for-each select="/Events/Event[@type='EventDetail'][position()<= 1]">
<br/>
<div class="event">
<xsl:apply-templates select="Performers"/>
</div>
</xsl:for-each>
</xsl:template>
<xsl:template match="Performers">
<xsl:for-each
select="Performer[not(PerformerParentID) and not(PerformerTypes/PerformerType[.='Group'])]">
<!-- Individual performers -->
<p>
<xsl:text>Featured speaker:</xsl:text>
<xsl:call-template name="printPerformerInfo"/>
</p>
</xsl:for-each>
<xsl:for-each select="Performer[PerformerTypes/PerformerType[.='Group']]">
<!-- Groups -->
<p>
<xsl:text>Performer Group:</xsl:text>
<xsl:value-of select="Name/FullName"/>
<xsl:variable name="moderators" select="key('moderators', PerformerID)"/>
<xsl:variable name="speakers" select="key('speakers', PerformerID)"/>
<p>
<label>Moderator<xsl:if test="count($moderators) > 1">s</xsl:if>: </label>
<xsl:for-each select="$moderators">
<xsl:call-template name="printPerformerInfo"/>
<xsl:if test="not(last() =position())">
<xsl:text>; </xsl:text>
</xsl:if>
</xsl:for-each>
<br/>
<xsl:for-each select="$speakers">
<label>Speaker: </label>
<xsl:call-template name="printPerformerInfo"/>
<xsl:if test="not(last() =position())">
<br/>
</xsl:if>
</xsl:for-each>
</p>
</p>
</xsl:for-each>
</xsl:template>
<xsl:template name="printPerformerInfo">
<xsl:choose>
<xsl:when test="WebPages/WebPage/URL != ''">
<a href="{WebPages/WebPage/URL}">
<xsl:value-of select="Name/FullName"/>
</a>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="Name/FullName"/>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="ProfessionalAffiliations/ProfessionalAffiliation/JobTitles/JobTitle != ''">,
<xsl:value-of select="ProfessionalAffiliations/ProfessionalAffiliation/JobTitles/JobTitle"
/>
</xsl:if>
<xsl:if test="ProfessionalAffiliations/ProfessionalAffiliation/OrganizationName != ''">, <xsl:choose>
<xsl:when
test="ProfessionalAffiliations/ProfessionalAffiliation/OrganizationWebPages/
WebPage/URL != ''">
<a
href="{ProfessionalAffiliations/ProfessionalAffiliation/OrganizationWebPages
/WebPage/URL}">
<xsl:value-of select="ProfessionalAffiliations/ProfessionalAffiliation/OrganizationName"
/>
</a>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="ProfessionalAffiliations/ProfessionalAffiliation/OrganizationName"/>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
On something like <?xml version="1.0" encoding="UTF-8"?> <Events> <View> <Timeframe>event</Timeframe> </View> <Event type="EventDetail"> <EventID>1300</EventID> <EventTitle>Daily recurring event 18</EventTitle> <DateTime> <TimeStamp>1157396400</TimeStamp> <StartDate>2006-09-04</StartDate> <StartTime>12:00:00</StartTime> <EndDate>2006-09-04</EndDate> <EndTime>12:00:00</EndTime> </DateTime> <Performers> <Performer> <PerformerID>2018</PerformerID> <Name> <FullName>Performer group</FullName> </Name> <PerformerTypes> <PerformerType>Group</PerformerType> </PerformerTypes> <WebPages> <WebPage>
<URL>http://www.joffrey.com/</URL> </WebPage> </WebPages> </Performer> <Performer> <PerformerID>2019</PerformerID> <Name> <FullName>Performer in Performer Group</FullName> </Name> <PerformerTypes>
<PerformerType>Moderator</PerformerType> </PerformerTypes> <ProfessionalAffiliations> <ProfessionalAffiliation> <JobTitles>
<JobTitle>Performer</JobTitle> </JobTitles>
<OrganizationName>Org</OrganizationName> <OrganizationWebPages> <WebPage>
<URL>http://www.org.com</URL> </WebPage> </OrganizationWebPages> </ProfessionalAffiliation> </ProfessionalAffiliations> <WebPages> <WebPage>
<URL>http://www.performer.com</URL>
</WebPage>
</WebPages>
<PerformerParentID>2018</PerformerParentID>
</Performer>
<Performer>
<PerformerID>2019</PerformerID>
<Name>
<FullName>Performer Speaker in Performer Group</FullName>
</Name>
<PerformerTypes>
<PerformerType>Speaker</PerformerType> </PerformerTypes> <ProfessionalAffiliations> <ProfessionalAffiliation> <JobTitles>
<JobTitle>Performer</JobTitle> </JobTitles>
<OrganizationName>Org</OrganizationName> <OrganizationWebPages> <WebPage>
<URL>http://www.org.com</URL> </WebPage> </OrganizationWebPages> </ProfessionalAffiliation> </ProfessionalAffiliations> <WebPages> <WebPage>
<URL>http://www.performer.com</URL> </WebPage> </WebPages> <PerformerParentID>2018</PerformerParentID> </Performer>
<Performer> <PerformerID>2019</PerformerID> <Name> <FullName>Performer InNoGroup</FullName> </Name> <PerformerTypes> <PerformerType>None</PerformerType> </PerformerTypes> <ProfessionalAffiliations> <ProfessionalAffiliation> <JobTitles> <JobTitle>Performer</JobTitle> </JobTitles> <OrganizationName>Org</OrganizationName> <OrganizationWebPages> <WebPage> <URL>http://www.org.com</URL> </WebPage> </OrganizationWebPages> </ProfessionalAffiliation> </ProfessionalAffiliations> <WebPages> <WebPage>
<URL>http://www.performer.com</URL> </WebPage> </WebPages>
</Performer> </Performers> </Event> </Events>
it gives Here are the events:
Featured speaker:Performer InNoGroup, Performer, Org
Performer Group:Performer group Moderator: Performer in Performer Group, Performer, Org Speaker: Performer Speaker in Performer Group, Performer, Org
Best Regards, George --------------------------------------------------------------------- George Cristian Bina <oXygen/> XML Editor, Schema Editor and XSLT Editor/Debugger http://www.oxygenxml.com
Allison Bloodworth wrote:Hi,information.
I want to create an XSL stylesheet that will display information on a calendar event. I have an XML document containing all the eventIn this our system, performers can be groups which contain otherperformers.If the performer is part of a group, it has a PerformerParentID.and
I am trying to create a stylesheet that goes through all the performersprints information first for only individual performers grouped byperformerwanttype(I know there are still some problems with this that I haven't completely worked out yet) and then prints the performer groups. Then Itheto recursively call my Performer template to print the performers that are part of the groups in the same way performers are printed out, but underappropriate group heading. Something like this:to
Featured speaker: Totally individual performer - in no group, Manager, IBM Performer Group: Group #1 Moderator: Performer #1 in Group #1, Facilitator, SAP Speaker: Performer #2 in Group #1, Manager, SAP
I first tried to use a global variable to count the number of recursive calls I wanted to do (I know that there are only two levels of performer groups in our systems so I stop there), but that didn't work. So I triedisn'tfollow Bob DuCharme's recommendation here: http://www.xml.com/pub/a/2001/08/01/gettingloopy.html?page=2 However, my implementation is slightly different as I have to use apply-templates instead of call-template since I'm changing the context node. But thisworking either, and when I test it out in Oxygen with Saxon 8b I'm gettingaThemessage that there are "Too many nested apply-templates calls. The stylesheet is probably looping." I am also the transform using PHP 5's standard XSLT processor and having the same problem.
Any thoughts or suggestions are appreciated! Here are snippets of the appropriate code:
<?xml version="1.0" encoding="UTF-8"?>
<Events>
<View>
<Timeframe>event</Timeframe> </View>
<Event type="EventDetail">
<EventID>1300</EventID>
<EventTitle>Daily recurring event 18</EventTitle>
<DateTime>
<TimeStamp>1157396400</TimeStamp>
<StartDate>2006-09-04</StartDate>
<StartTime>12:00:00</StartTime>
<EndDate>2006-09-04</EndDate>
<EndTime>12:00:00</EndTime>
</DateTime>
<Performers>
<Performer>
<PerformerID>2018</PerformerID>
<Name>
<FullName>Performer group</FullName>
</Name>
<PerformerTypes>
<PerformerType>Group</PerformerType>
</PerformerTypes>
<WebPages>
<WebPage>
<URL>http://www.joffrey.com/</URL>
</WebPage>
</WebPages>
</Performer>
<Performer>
<PerformerID>2019</PerformerID>
<Name>
<FullName>Performer in Performer
Group</FullName>
</Name>
<PerformerTypes>
<PerformerType>Moderator</PerformerType>
</PerformerTypes>
<ProfessionalAffiliations>
<ProfessionalAffiliation>
<JobTitles>
<JobTitle>Performer</JobTitle>
</JobTitles>
<OrganizationName>Org</OrganizationName>
<OrganizationWebPages>
<WebPage>
<URL>http://www.org.com</URL>
</WebPage>
</OrganizationWebPages>
</ProfessionalAffiliation>
</ProfessionalAffiliations>
<WebPages>
<WebPage>
<URL>http://www.performer.com</URL>
</WebPage>
</WebPages>
<PerformerParentID>2018</PerformerParentID>
</Performer>
</Performers>
</Event>
</Events>
----------------------------------------
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!--- There are a bunch of variables here that I didn't include and the
stylesheet is greatly simplified but can send full info on if necessary.recursive call is marked "HERE IS THE RECURSIVE CALL" below. -->test="../../ProfessionalAffiliations/ProfessionalAffiliation/JobTitles/JobTi
<xsl:template match="/"> <!-- Determine which TIMEFRAME to render --> <html> <body> Here are the events: <xsl:choose> <xsl:when test="/Events/View/Timeframe='event'"> <xsl:call-template name="TimeframeEvent"/> </xsl:when> <xsl:when test="/Events/View/Timeframe='day'"> Do nothing </xsl:when> </xsl:choose> </body> </html> </xsl:template>
<xsl:template name="TimeframeEvent">
<xsl:for-each select="/Events/Event[@type='EventDetail'][position() <= 1]"> <br /> <div class="event">
<!-- Performers DONE-->
About to call the Performers template and the current node is <xsl:value-of select="name()"/> <xsl:apply-templates select="Performers"> <xsl:with-param name="performerLevels" select="2"/> </xsl:apply-templates> </div> </xsl:for-each> </xsl:template>
<xsl:template match="Performers"> <xsl:param name="performerLevels">2</xsl:param> <!-- Moderators --> <xsl:if test="Performer/PerformerTypes/PerformerType[.='Moderator']"> <p> <label>Moderator<xsl:if test="count(Performer/PerformerTypes/PerformerType[.='Moderator']) > 1">s</xsl:if>: </label> <xsl:for-each select="Performer/PerformerTypes/PerformerType[.='Moderator']"> <xsl:if test="count(../../PerformerParentID) = 0"> <xsl:choose> <xsl:when test="../../WebPages/WebPage/URL != ''"> <a href="{../../WebPages/WebPage/URL}"><xsl:value-of select="../../Name/FullName"/></a> </xsl:when> <xsl:otherwise> <xsl:value-of select="../../Name/FullName"/> </xsl:otherwise> </xsl:choose>
<xsl:if
select="../../ProfessionalAffiliations/ProfessionalAffiliation/JobTitles/Jobtle != ''">, <xsl:value-of
test="../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationNamTitle"/> </xsl:if>
<xsl:if
e != ''">,test="../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationWeb
<xsl:choose> <xsl:when
href="{../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationWePages/WebPage/URL != ''"> <a
bPages/WebPage/URL}"><xsl:value-ofselect="../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationN
select="../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationName"/></a> </xsl:when> <xsl:otherwise> <xsl:value-of
test="../../ProfessionalAffiliations/ProfessionalAffiliation/JobTitles/JobTiame"/> </xsl:otherwise> </xsl:choose> </xsl:if>
<xsl:if test="not(last() = position())"> <xsl:text>; </xsl:text> </xsl:if> </xsl:if> </xsl:for-each> </p> </xsl:if> <!-- Performer Group --> <xsl:if test="Performer/PerformerTypes/PerformerType[.='Group']"> <p> <label>Performer Group<xsl:if test="count(Performer/PerformerTypes/PerformerType[.='Group']) > 1">s</xsl:if>: </label> <xsl:for-each select="Performer/PerformerTypes/PerformerType[.='Group']"> <xsl:variable name="groupID" select="../../PerformerID"/>
<xsl:choose> <xsl:when test="../../WebPages/WebPage/URL != ''"> <a href="{../../WebPages/WebPage/URL}"><xsl:value-of select="../../Name/FullName"/></a> </xsl:when> <xsl:otherwise> <xsl:value-of select="../../Name/FullName"/> </xsl:otherwise> </xsl:choose>
<xsl:if
select="../../ProfessionalAffiliations/ProfessionalAffiliation/JobTitles/Jobtle != ''">, <xsl:value-of
test="../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationNamTitle"/> </xsl:if>
<xsl:if
e != ''">,test="../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationWeb
<xsl:choose> <xsl:when
href="{../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationWePages/WebPage/URL != ''"> <a
bPages/WebPage/URL}"><xsl:value-ofselect="../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationN
select="../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationName"/></a> </xsl:when> <xsl:otherwise> <xsl:value-of
groupIDame"/> </xsl:otherwise> </xsl:choose> </xsl:if>
<xsl:if test="not(last() = position())"> <xsl:text>; </xsl:text> </xsl:if> <xsl:for-each select="../../../Performer"> I am inside the for-each and PerformerParentID is <xsl:value-of select="PerformerParentID"/> andis <xsl:value-of select="$groupID"/><br/> <xsl:if test="PerformerParentID = $groupID"> Inside the current node is <xsl:value-of select="name()"/><br/> <xsl:if test="$performerLevels > 0"> performer levels are <xsl:value-of select="$performerLevels"/><br/> <!--HERE IS THE RECURSIVE CALL--> <xsl:apply-templates select="../../Performers"/> </xsl:if> </xsl:if> </xsl:for-each> </xsl:for-each> </p> </xsl:if> </xsl:template> <!-- NOTE: END PERFORMERS TEMPLATE ////////////////////////////////// --> </xsl:stylesheet>
Allison Bloodworth Principal Administrative Analyst Technology Program Office University of California, Berkeley (415) 377-8243 abloodworth@xxxxxxxxxxxx
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
RE: [xsl] Problem using recursive a, Allison Bloodworth | Thread | RE: [xsl] Problem using recursive a, Allison Bloodworth |
Re: [xsl] outputting <?xml version=, Abel Braaksma | Date | RE: [xsl] outputting <?xml version=, Ian Murphy |
Month |