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 April 10th, 2010, 10:42 PM
Authorized User
 
Join Date: Jul 2009
Posts: 23
Thanks: 5
Thanked 0 Times in 0 Posts
Default Optimizing function to convert string to ISO date

Hi - I have a function that I invoke repeatedly in my stylesheet to convert a string of the form 04/09/2010 or 4/09/2010 or 4/9/2010 or 04/9/2010 to the ISO format 2010-04-09. I ran a profiler on my stylesheet and it appears this function is slowing it down quite a bit. Below is the function. Would appreciate any tips to improve the performance. Thanks!

Code:
	<xsl:function name="lbs:formatDateISO" as="xs:date">
		<xsl:param name="varDate" as="xs:string"/>
		<xsl:value-of select="xs:date(concat(tokenize($varDate,'/')[3],'-',substring('0',1,2 - string-length(tokenize($varDate,'/')[1])),tokenize($varDate,'/')[1],'-',substring('0',1,2 - string-length(tokenize($varDate,'/')[2])),tokenize($varDate,'/')[2]))" /> 
	</xsl:function>
 
Old April 11th, 2010, 02:17 AM
Authorized User
 
Join Date: Jul 2009
Posts: 23
Thanks: 5
Thanked 0 Times in 0 Posts
Default

I rewrote this function to avoid doing multiple tokenize's and avoid substring... not sure this is the best that can be done though:

Code:
	<xsl:function name="lbs:formatDateISO" as="xs:date">
		<xsl:param name="varDate" as="xs:string"/>
		<xsl:variable name="tokArray" select="tokenize($varDate,'/')"></xsl:variable>
		<xsl:variable name="year"><xsl:value-of select="$tokArray[3]"></xsl:value-of></xsl:variable>
		<xsl:variable name="varMonth"><xsl:value-of select="$tokArray[1]"></xsl:value-of></xsl:variable>
		<xsl:variable name="varDay"><xsl:value-of select="$tokArray[2]"></xsl:value-of></xsl:variable>
		<xsl:variable name="month">
			<xsl:choose>
				<xsl:when test="string-length($varMonth) &lt; 2"><xsl:value-of select="concat('0',$varMonth)"></xsl:value-of></xsl:when>
				<xsl:otherwise><xsl:value-of select="$varMonth"></xsl:value-of></xsl:otherwise>
			</xsl:choose>
		</xsl:variable>
		<xsl:variable name="day">
			<xsl:choose>
				<xsl:when test="string-length($varDay) &lt; 2"><xsl:value-of select="concat('0',$varDay)"></xsl:value-of></xsl:when>
				<xsl:otherwise><xsl:value-of select="$varDay"></xsl:value-of></xsl:otherwise>
			</xsl:choose>
		</xsl:variable>
		
		<xsl:value-of select="xs:date(concat($year,'-',$month,'-',$day))" /> 
	</xsl:function>
 
Old April 11th, 2010, 04:54 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

Performance may depend on the product you are using, but as a general rule, if you place less reliance on the optimizer then the code will run as well or better in most products. It's likely that your product doesn't eliminate common sub-expressions, and therefore evaluates tokenize($x, '/') repeatedly, so pulling this out into a variable is definitely a good thing to do.

The construct <xsl:variable name="x"><xsl:value-of select="y"/></xsl:variable> is intrinsically inefficient because you're asking the processor to build a tree. It's much better to use <xsl:variable name="x" select="y"/>. Saxon tries hard to optimize this one by looking at all the references to the variable to check that you're not using the value as a tree, but it's always best to avoid relying on such optimizations if you can.

Similarly, don't use xsl:value-of to return the result of a function - use xsl:sequence. By using xsl:value-of you are creating a text node, which is then atomized to create a string. The same is true inside the xsl:when and xsl:otherwise conditionals.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
 
Old April 11th, 2010, 05:31 AM
mhkay's Avatar
Wrox Author
 
Join Date: Apr 2004
Posts: 4,962
Thanks: 0
Thanked 292 Times in 287 Posts
Default

If the above suggestions aren't enough, then getting rid of the tokenize() call entirely might prove useful - you would have to measure it to test the effect. Something like this:

Code:
<xsl:function name="..." as="xs:date">
  <xsl:param name="varDate" as="xs:string">
  <xsl:variable name="varDate"
    select="if (substring($varDate, 2, 1) eq '/') then concat('0', $varDate) else $varDate"/>
  <xsl:variable name="varDate"
    select="if (substring($varDate, 5, 1) eq '/') then concat(substring($varDate, 1, 3), '0', substring($varDate, 4)) else $varDate"/>
  <xsl:sequence select="xs:date(concat(substring($varDate, 6, 4), '-', substring($varDate, 4, 2), '-', substring($varDate, 1, 2)))"/>
</xsl:function>
Another approach would be to have an outer choose that tests whether the input string has length 8, 9, or 10, and take different action for the three cases.
__________________
Michael Kay
http://www.saxonica.com/
Author, XSLT 2.0 and XPath 2.0 Programmer\'s Reference
 
Old April 12th, 2010, 02:06 AM
Authorized User
 
Join Date: Jul 2009
Posts: 23
Thanks: 5
Thanked 0 Times in 0 Posts
Default

Thanks for the tips, Michael. I changed the function to the one shown below (I removed all tokenize as this approach helped the most) and this improved performance by around 20%. The change from value-of to sequence improved performance by an additional 25%.

Code:
	<xsl:function name="lbs:formatDateISO" as="xs:date">
		<xsl:param name="varDate" as="xs:string"/>
		<xsl:variable name="strLen" select="string-length($varDate)"></xsl:variable>
		<xsl:choose>
			<xsl:when test="$strLen=10"> 
				<xsl:sequence select="xs:date(concat(substring($varDate, 7, 4), '-', substring($varDate, 1, 2), '-', substring($varDate, 4, 2)))"/>
			</xsl:when>
			<xsl:when test="$strLen=8"> 
				<xsl:sequence select="xs:date(concat(substring($varDate, 5, 4), '-0', substring($varDate, 1, 1), '-0', substring($varDate, 3, 1)))"/>				
			</xsl:when>
			<xsl:otherwise>
				<xsl:choose>
					<xsl:when test="substring($varDate, 2, 1) eq '/'"> 
						<xsl:sequence select="xs:date(concat(substring($varDate, 6, 4), '-0', substring($varDate, 1, 1), '-', substring($varDate, 3, 2)))"/>
					</xsl:when>
					<xsl:otherwise> 
						<xsl:sequence select="xs:date(concat(substring($varDate, 6, 4), '-', substring($varDate, 1, 2), '-0', substring($varDate, 4, 1)))"/>
					</xsl:otherwise>
				</xsl:choose>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>
However, one interesting thing I noticed was that taking the tokenize out into a variable degraded performance a bit.

I'm using the "Saxon-HE 9.2.0.6" XSLT processor within the Oxygen XML/XSLT editor for development/testing. Eventually, I plan to invoke this stylesheet via .NET using the Saxon library.

The above function and the one below are still the largest contributors to the execution time. Not sure if there's anything more that can be done to further improve performance? I tried string-join instead of concat but that seems to degrade performance a bit. The stylesheet I'm working on now takes about 37 secs on a small input dataset and takes 190 secs on one of the larger ones (it used to take around 6 mins before the above mentioned changes). My goal is to get the larger one to execute in under a minute.. not quite sure how realistic this is.. Thanks!

Code:
	<xsl:function name="lbs:formatISODateToString" as="xs:string">
		<xsl:param name="varDate" as="xs:date"/>
		<xsl:sequence select="concat(substring(xs:string($varDate),6,2),'/',substring(xs:string($varDate),9,2),'/',substring(xs:string($varDate),1,4))"/>
	</xsl:function>





Similar Threads
Thread Thread Starter Forum Replies Last Post
convert string to function austinf Javascript 3 September 19th, 2008 03:25 AM
SQL and ISO date problems CallumBeveridge SQL Server 2000 6 August 17th, 2007 02:14 PM
ISO Date Problem chrislepingwell SQL Server 2000 2 May 30th, 2006 12:52 PM
convert string to date deeptibg SQL Server DTS 1 December 22nd, 2005 08:47 PM
Convert String Date to Date for a SQL Query tdaustin Classic ASP Basics 4 July 7th, 2003 06:01 PM





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