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 January 4th, 2011, 01:18 PM
Registered User
 
Join Date: Jan 2011
Posts: 5
Thanks: 0
Thanked 0 Times in 0 Posts
Default Iterating Through Pipe Separated List Causing StackOverflow

I am using ant1.8 on ubuntu 10.10 and also xslt1.0.

I have 2 lists of items:

Code:
ProductID=8901|8902|8903|8904|8905|8906|8907|8908|9089
ProductDisplayName=Song1|Song2|Song3|Song4|Song5|Song6|Song7|Song8|Song9
That I need to transform to look like:

Code:
<Product>
<subscription/>
<ID>8901</ID>
<title>Song1</title>
</Product>
<Product>
<subscription/>
<ID>8902</ID>
<title>Song2</title>
</Product>
<Product>
<subscription/>
<ID>8903</ID>
<title>Song3</title>
</Product>
And so on and so forth. I feel like I am close but the loop that I am using is causing a stack overflow. Here is my template that i created:

Code:
<xsl:template name="parseSubscription">
	<xsl:param name="parseId" select="normalize-space($ProductID)" />
	<xsl:param name="parseDisplayName" select="normalize-space($ProductDisplayName)" />      
	<xsl:choose>
		<xsl:when test="nscl:capitalize($ProductType) = 'Free'">
			<Product>
				<freeAccess />
			</Product>
		</xsl:when>
		<xsl:otherwise>
		<xsl:if test="string-length($parseId) &gt; 0">
		<Product>
		<subscription/>
			<ID>
				<xsl:choose>
					<xsl:when test="contains($parseId, '|')">
						<xsl:value-of select="normalize-space(substring-before($parseId, '|'))" />
					</xsl:when>
					<xsl:otherwise>
						<xsl:value-of select="normalize-space($parseId)" />
					</xsl:otherwise>
				</xsl:choose>
			</ID>
			<title>
				<xsl:choose>
					<xsl:when test="contains($parseDisplayName, '|')">
						<xsl:value-of select="normalize-space(substring-before($parseDisplayName, '|'))" />
					</xsl:when>
					<xsl:otherwise>
						<xsl:value-of select="normalize-space($parseDisplayName)" />
					</xsl:otherwise>
				</xsl:choose>
			</title>
		</Product>

		<!-- Recurse -->
		<xsl:call-template name="parseSubscription">
			<xsl:with-param name="parseId" select="substring-after(normalize-space($ProductID), '|')" />
			<xsl:with-param name="parseDisplayName" select="substring-after(normalize-space($ProductDisplayName), '|')" />
		</xsl:call-template>
		</xsl:if>
		</xsl:otherwise>
	</xsl:choose>
</xsl:template>
and how it is called:

Code:
<xsl:call-template name="parseSubscription">
	<xsl:with-param name="parseId" select="$ProductID" />
	<xsl:with-param name="parseDisplayName" select="$ProductDisplayName" />
</xsl:call-template>
If I remove the recursive call ant is able to compile the xsl and transform the file just fine, but of course I only get the first pair:

Code:
<Product>
<subscription/>
<ID>8901</ID>
<title>Song1</title>
</Product>
and of course I need it to continue to loop through until it reaches the end of the list. I have some kind of issue (obviously), can anyone help me identify it? Or perhaps just a better approach?

Thanks!
 
Old January 4th, 2011, 01:40 PM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Well the request for a "better" approach begs for the suggestion to use XSLT 2.0 instead with Saxon 9, there all you need is e.g.
Code:
tokenize($ProductID, '|')
to find the different ids in your '|' separated string.

With XSLT 1.0 and a recursive template you could use
Code:
  <xsl:choose>
     <xsl:when test="not(contains($parseId, '|'))">
        <!-- now output stuff here without recursing -->
        <Id><xsl:value-of select="$parseId"/></Id>
        ...
     </xsl:when>
     <xsl:otherwise>
        <!-- output stuff here and recurse -->
        <Id><xsl:value-of select="substring-before($parseId, '|')"/></Id>
        ....
        <xsl:call-template name="parseSubscription">
           <xsl:with-param name="parseId" select="substring-after($parseId, '|')"/>
            ...
         </xsl:call-template>
     </xsl:otherwise>
  </xsl:choose>
Of course such approach could still run out of stack space for long lists if the processor does not implement tail recursion.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old January 4th, 2011, 01:56 PM
Registered User
 
Join Date: Jan 2011
Posts: 5
Thanks: 0
Thanked 0 Times in 0 Posts
Default

SOLVED!

I finally found the problem and it was extremely minor, thats how it usually is, right?

It was in my recursive call, OF COURSE.

Change the recursive call from:

Code:
<!-- Recurse -->
		<xsl:call-template name="parseSubscription">
			<xsl:with-param name="parseId" select="substring-after(normalize-space($ProductID), '|')" />
			<xsl:with-param name="parseDisplayName" select="substring-after(normalize-space($ProductDisplayName), '|')" />
		</xsl:call-template>
to this:

Code:
<!-- Recurse --> 
		<xsl:call-template name="parseSubscription">
			<xsl:with-param name="parseId" select="substring-after(normalize-space($parseId), '|')" />
			<xsl:with-param name="parseDisplayName" select="substring-after(normalize-space($parseDisplayName), '|')" />
		</xsl:call-template>
Which makes sense to me in that if I kept passing the value of original variables ($ProductId, $ProductDisplayName) then it would never get to the end of the list. Instead I had to call the template recursively with the already parsed values in $parseId and $parseDisplayName so that it could actually move through the list.





Similar Threads
Thread Thread Starter Forum Replies Last Post
Populate a list box from comma separated values CoderNH Access VBA 3 October 20th, 2008 08:37 AM
convert list of ';' separated values --> elements Condor76 XSLT 1 June 11th, 2007 02:56 PM
comma separated list MunishBhatia SQL Server 2000 11 March 21st, 2007 03:56 PM
selecting elements from comma separated list rjonk XSLT 4 September 29th, 2006 08:46 AM
comma separated list of attributes rjonk XSLT 3 September 27th, 2006 11:52 AM





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