[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

RE: [xsl] Problem using recursive apply-templates calls


Subject: RE: [xsl] Problem using recursive apply-templates calls
From: "Allison Bloodworth" <abloodworth@xxxxxxxxxxxx>
Date: Fri, 15 Sep 2006 14:44:03 -0700

Sorry, one more thing. 

The reason I thought it was OK to make this apply-templates call is that I
did want to iterate through the performers again in the same context, but I
thought the performerLevels variable I sent would limit it so that there
would only be one more iteration through all the performers. I think that
variable isn't being decremented properly, or maybe this just won't work for
some other reason I don't know about.

-----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()&lt;= 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) &gt; 
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, 
> 
> I want to create an XSL stylesheet that will display information on a
> calendar event. I have an XML document containing all the event
information.
> In this our system, performers can be groups which contain other
performers.
> If the performer is part of a group, it has a PerformerParentID. 
> 
> I am trying to create a stylesheet that goes through all the performers
and
> prints information first for only individual performers grouped by
performer
> type(I know there are still some problems with this that I haven't
> completely worked out yet) and then prints the performer groups. Then I
want
> to recursively call my Performer template to print the performers that are
> part of the groups in the same way performers are printed out, but under
the
> appropriate group heading. Something like this:
> 
> 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 tried
to
> follow 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 this
isn't
> working either, and when I test it out in Oxygen with Saxon 8b I'm getting
a
> message 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.
The
> recursive call is marked "HERE IS THE RECURSIVE CALL" below. -->
> 
> <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()
> &lt;= 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']) &gt;
> 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
>
test="../../ProfessionalAffiliations/ProfessionalAffiliation/JobTitles/JobTi
> tle != ''">,
> 						<xsl:value-of
>
select="../../ProfessionalAffiliations/ProfessionalAffiliation/JobTitles/Job
> Title"/>
> 					</xsl:if>
> 
> 					<xsl:if
>
test="../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationNam
> e != ''">,
> 
> 						<xsl:choose>
> 							<xsl:when
>
test="../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationWeb
> Pages/WebPage/URL != ''">
> 								<a
>
href="{../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationWe
> bPages/WebPage/URL}"><xsl:value-of
>
select="../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationN
> ame"/></a>
> 							</xsl:when>
> 							<xsl:otherwise>
> 	
> <xsl:value-of
>
select="../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationN
> ame"/>
> 							</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']) &gt;
> 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
>
test="../../ProfessionalAffiliations/ProfessionalAffiliation/JobTitles/JobTi
> tle != ''">,
> 					<xsl:value-of
>
select="../../ProfessionalAffiliations/ProfessionalAffiliation/JobTitles/Job
> Title"/>
> 				</xsl:if>
> 
> 				<xsl:if
>
test="../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationNam
> e != ''">,
> 
> 					<xsl:choose>
> 						<xsl:when
>
test="../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationWeb
> Pages/WebPage/URL != ''">
> 							<a
>
href="{../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationWe
> bPages/WebPage/URL}"><xsl:value-of
>
select="../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationN
> ame"/></a>
> 						</xsl:when>
> 						<xsl:otherwise>
> 							<xsl:value-of
>
select="../../ProfessionalAffiliations/ProfessionalAffiliation/OrganizationN
> ame"/>
> 						</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"/> and
groupID
> is <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