1
\$\begingroup\$

I am trying to learn to format XSL more efficiently. I can tell by the definition of duplicate variables and nearly identical templates that I did not create this efficiently at all. How could I have formed this better?

Here is my XSL: you can see all of it at http://wwwstage.samford.edu/calendar/ADCCancel.xsl
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:r25="http://www.collegenet.com/r25"
xmlns:r25fn="http://www.collegenet.com/r25/functions"
xmlns:xl="http://www.w3.org/1999/xlink"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
version="2.0">
<xsl:output
 method="xml"
 encoding="UTF-8"
 version="1.0"/>
<xsl:template match="/">
 <xsl:variable name="pubdate">
 <xsl:value-of select="r25:events/@pubdate"/>
 </xsl:variable>
 <xsl:element name="CALENDAR_ENTERPRISE">
 <xsl:attribute name="Created">
 <xsl:value-of select="$pubdate"/>
 </xsl:attribute>
 <xsl:element name="TIMEZONE">
 <xsl:attribute name="type">group</xsl:attribute>
 <xsl:element name="GMTOffset">
 <xsl:attribute name="type">text</xsl:attribute>
 <xsl:text>-6</xsl:text>
 </xsl:element>
 </xsl:element> 
 <xsl:apply-templates select="r25:events/r25:event/r25:profile">
 <xsl:sort select="r25:init_start_dt"/>
 </xsl:apply-templates>
 </xsl:element>
</xsl:template>
<xsl:template match="r25:profile">
 <xsl:variable name="evtname" select="../r25:event_name"/>
 <xsl:variable name="evttitle" select="../r25:event_title"/>
 <xsl:variable name="refno" select="../r25:event_locator"/>
 <xsl:variable name="profilename" select="r25:profile_name"/>
 <xsl:variable name="desc" select="../r25:event_text[r25:text_type_id=1]/r25:text"/>
 <xsl:variable name="relweb" select="../r25:custom_attribute[r25:attribute_id=-1]/r25:attribute_value"/>
 <xsl:variable name="eventImage" select="../r25:custom_attribute[r25:attribute_id=-4]/r25:attribute_value"/>
 <xsl:variable name="ticket" select="../r25:custom_attribute[r25:attribute_id=4]/r25:attribute_value"/>
 <xsl:variable name="flyer" select="../r25:custom_attribute[r25:attribute_id=6]/r25:attribute_value"/>
 <xsl:variable name="contact" select="../r25:role[r25:role_id = -1]/r25:contact"/>
 <xsl:variable name="catsno" select="count(../r25:category)"/>
 <xsl:variable name="org" select="../r25:organization[r25:primary='T']/r25:organization_name"/>
 <xsl:variable name="created_dt" select="../r25:event_history[1]/r25:history_dt"/>
 <xsl:variable name="usetitle" select="../r25:custom_attribute[r25:attribute_id=6]/r25:attribute_value"/>
 <xsl:choose>
 <xsl:when test="r25:rec_type_id != 2">
 <xsl:call-template name="RecurringEvent">
 <xsl:with-param name="evtname" select="$evtname"/>
 <xsl:with-param name="evttitle" select="$evttitle"/>
 <xsl:with-param name="refno" select="$refno"/>
 <xsl:with-param name="profilename" select="$profilename"/>
 <xsl:with-param name="desc" select="$desc"/>
 <xsl:with-param name="relweb" select="$relweb"/>
 <xsl:with-param name="ticket" select="$ticket"/>
 <xsl:with-param name="flyer" select="$flyer"/>
 <xsl:with-param name="evtimg" select="$eventImage"/>
 <xsl:with-param name="contact" select="$contact"/>
 <xsl:with-param name="catsno" select="$catsno"/>
 <xsl:with-param name="org" select="$org"/>
 <xsl:with-param name="startdate" select="r25:init_start_dt"/>
 <xsl:with-param name="enddate" select="r25:init_end_dt"/>
 <xsl:with-param name="spaces" select="r25:reservation/r25:space_reservation"/>
 <xsl:with-param name="created" select="$created_dt"/>
 <xsl:with-param name="usetitle" select="$usetitle"/>
 </xsl:call-template>
 </xsl:when>
 <xsl:otherwise>
 <xsl:apply-templates select="r25:reservation">
 <xsl:with-param name="evtname" select="$evtname"/>
 <xsl:with-param name="evttitle" select="$evttitle"/>
 <xsl:with-param name="refno" select="$refno"/>
 <xsl:with-param name="profilename" select="$profilename"/>
 <xsl:with-param name="desc" select="$desc"/>
 <xsl:with-param name="relweb" select="$relweb"/>
 <xsl:with-param name="evtimg" select="$eventImage"/>
 <xsl:with-param name="ticket" select="$ticket"/>
 <xsl:with-param name="flyer" select="$flyer"/>
 <xsl:with-param name="contact" select="$contact"/>
 <xsl:with-param name="catsno" select="$catsno"/>
 <xsl:with-param name="org" select="$org"/>
 <xsl:with-param name="created" select="$created_dt"/>
 <xsl:with-param name="usetitle" select="$usetitle"/>
 </xsl:apply-templates>
 </xsl:otherwise>
 </xsl:choose>
</xsl:template>
<xsl:template name="RecurringEvent">
 <!-- Setup variables for different parts of the XML for each event -->
 <xsl:param name="evtname"/>
 <xsl:param name="evttitle"/>
 <xsl:param name="refno"/>
 <xsl:param name="profilename"/>
 <xsl:param name="desc"/>
 <xsl:param name="relweb"/>
 <xsl:param name="ticket"/>
 <xsl:param name="flyer"/>
 <xsl:param name="evtimg"/>
 <xsl:param name="contact"/>
 <xsl:param name="catsno"/>
 <xsl:param name="org"/>
 <xsl:param name="startdate"/>
 <xsl:param name="laststartdate"/>
 <xsl:param name="enddate"/>
 <xsl:param name="spaces"/>
 <xsl:param name="created"/>
 <xsl:param name="usetitle"/>
XSL TO CREATE EVENTNODES
</xsl:template>
<xsl:template match="r25:reservation">
 <!-- Setup variables for different parts of the XML for each event -->
 <xsl:param name="evtname"/>
 <xsl:param name="evttitle"/>
 <xsl:param name="refno"/>
 <xsl:param name="profilename"/>
 <xsl:param name="desc"/>
 <xsl:param name="relweb"/>
 <xsl:param name="evtimg"/>
 <xsl:param name="ticket"/>
 <xsl:param name="flyer"/>
 <xsl:param name="contact"/>
 <xsl:param name="catsno"/>
 <xsl:param name="org"/>
 <xsl:param name="created"/>
 <xsl:variable name="startdate" select="r25:event_start_dt"/>
 <xsl:variable name="enddate" select="r25:event_end_dt"/>
 <xsl:variable name="spaces" select="r25:space_reservation"/>
 /// xsl to create Event Nodes
 </xsl:template>
<xsl:template match="r25:category">
 <xsl:variable name="goodcategories">
 <!-- Only push marketing categories to the calendar. The list below represents their IDs -->
 <xsl:variable name="isinlist">
 <xsl:value-of select="index-of((31,32,33,35,43,46,101,104,105,106,107,108,125,125,127,128,129),number(r25:category_id))" />
 </xsl:variable>
 <xsl:if test="$isinlist != ''">
 <xsl:value-of select="concat(r25:category_name,'||')"/>
 </xsl:if>
 </xsl:variable>
 <xsl:value-of select="$goodcategories"/> 
</xsl:template>
<xsl:template match="r25:rec_type_id"> 
<!-- This translates the R25 recurrence ID into something ADC understands based on http://knowledge25.collegenet.com/display/WSW/Profile+information-->
 <xsl:param name="code"/>
 <xsl:variable name="pattern" select="substring($code,1,2)"/>
 <xsl:element name="RecurType">
 <xsl:choose> 
<!--rec type of 0 means there are no recurrences. it is just a one-off event -->
 <xsl:when test=". = 0">
 <xsl:text>One Time</xsl:text>
 </xsl:when> 
<!--rec type of 2 means there are is a meeting pattern. the first 2 letters define the pattern. --> 
 <xsl:when test=". = 1">
 <xsl:choose>
 <xsl:when test="substring($pattern,1,1) = 'W'">
 <xsl:text>Weekly</xsl:text>
 <xsl:value-of select="substring($pattern,2,1)"/>
 </xsl:when> 
<!--Set if monthly--> 
 <xsl:when test="substring($pattern,1,1) = 'M'">
 <xsl:text>Monthly by Date</xsl:text>
 <!--Unlike the others, the monthly patterns list the number on the 3rd character -->
 <xsl:value-of select="substring($code,3,1)"/>
 </xsl:when> 
<!--Set if daily-->
 <xsl:when test="substring($pattern,1,1) = 'D'">
 <xsl:text>Interval</xsl:text>
 <xsl:value-of select="substring($pattern,2,1)"/>
 </xsl:when>
 <xsl:otherwise></xsl:otherwise>
 </xsl:choose>
 </xsl:when>
 <xsl:when test=". = 2">
 <xsl:text>Custom</xsl:text>
 </xsl:when>
 <xsl:otherwise>
 <xsl:text>Otherwise</xsl:text>
 </xsl:otherwise>
 </xsl:choose>
 </xsl:element>
 <xsl:element name="RecurEndDate">
 <xsl:attribute name="type">text</xsl:attribute>
 <xsl:call-template name="parse-profile-code">
 <xsl:with-param name="ProfileCode" select="$code"/>
 <xsl:with-param name="return">Date</xsl:with-param>
 </xsl:call-template>
 </xsl:element>
 <xsl:element name="RecurDays">
 <xsl:attribute name="type">text</xsl:attribute>
 <!-- The following if statement is to take into account the rule mentioned on pg 8 
 of the import guide stating this is only supposed to be used if the recur type is weekly -->
 <xsl:if test="substring($pattern,1,1) = 'W'">
 <xsl:call-template name="parse-profile-code">
 <xsl:with-param name="ProfileCode" select="$code"/>
 <xsl:with-param name="return">Days</xsl:with-param>
 </xsl:call-template>
 </xsl:if>
 </xsl:element>
</xsl:template>
<xsl:template name="parse-profile-code">
 <xsl:param name="ProfileCode"/>
 <xsl:param name="return"/>
 <xsl:analyze-string select="$ProfileCode" regex="^([DWMY])([MDP]?)([0-9]*)\s?(.*)?">
 <xsl:matching-substring>
 <xsl:variable name="Rest">
 <xsl:value-of select="regex-group(4)"/>
 </xsl:variable>
 <xsl:variable name="Until">
 <!-- Build the recur end date from the R25 profile code and store in a variable named until-->
 <xsl:choose>
 <xsl:when test="$return='Date'">
 <xsl:analyze-string select="$Rest" regex="([0-9][0-9]*T[0-9]*([\-+][0-9]*|Z)?|#[0-9]*)">
 <xsl:matching-substring>
 <!--The profile code lacks the necessary dashes to perform the format dateTime function. This inserts them in where needed. -->
 <xsl:value-of select="substring(regex-group(1),1,4)"/>
 <xsl:text>-</xsl:text>
 <xsl:value-of select="substring(regex-group(1),5,2)"/>
 <xsl:text>-</xsl:text>
 <xsl:value-of select="substring(regex-group(1),7,2)"/>
 </xsl:matching-substring>
 </xsl:analyze-string>
 </xsl:when>
 <xsl:when test="$return='Days'">
 <xsl:analyze-string select="$Rest" regex="([0-9][0-9]*T[0-9]*([\-+][0-9]*|Z)?|#[0-9]*)">
 <xsl:matching-substring>
 <xsl:value-of select="normalize-space(regex-group(1))"/>
 </xsl:matching-substring>
 </xsl:analyze-string>
 </xsl:when>
 </xsl:choose>
 </xsl:variable>
 <xsl:variable name="Days">
 <xsl:choose>
 <xsl:when test="string-length($Until) = 0">
 <xsl:value-of select="$Rest"/>
 </xsl:when>
 <xsl:otherwise>
 <xsl:value-of select="normalize-space(substring-before($Rest,$Until))"/>
 </xsl:otherwise>
 </xsl:choose>
 </xsl:variable>
 <xsl:choose>
 <xsl:when test="$return = 'Date'">
 <xsl:value-of select="format-date($Until,'[M]/[D01]/[Y]')"/>
 </xsl:when>
 <xsl:when test="$return = 'Days'">
 <xsl:call-template name="listdays">
 <xsl:with-param name="daylist">
 <xsl:value-of select="$Days"/>
 </xsl:with-param>
 </xsl:call-template>
 </xsl:when>
 </xsl:choose> 
 </xsl:matching-substring>
 </xsl:analyze-string> 
</xsl:template>
<xsl:template name="listdays">
 <xsl:param name="daylist"/>
 <xsl:variable name="tokenizedDayList" select="tokenize($daylist,'\s+')"/>
 <xsl:for-each select="$tokenizedDayList">
 <xsl:if test=". = 'MO'">Monday</xsl:if>
 <xsl:if test=". = 'TU'">Tuesday</xsl:if>
 <xsl:if test=". = 'WE'">Wednesday</xsl:if>
 <xsl:if test=". = 'TH'">Thursday</xsl:if>
 <xsl:if test=". = 'FR'">Friday</xsl:if>
 <xsl:if test=". = 'SA'">Saturday</xsl:if>
 <xsl:if test=". = 'SU'">Sunday</xsl:if>
 <xsl:if test=". != $tokenizedDayList[last()]">
 <xsl:text>,</xsl:text>
 </xsl:if> 
 </xsl:for-each>
</xsl:template>

Here is a sample of the xml file being transformed: http://wwwstage.samford.edu/calendar/sampler25.xml

And here is a sample of the output I am producing: http://wwwstage.samford.edu/calendar/ADECancel.aspx

asked Jun 30, 2012 at 14:37
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Some tips to improve your coding:

(a) don't do this:

<xsl:variable name="pubdate">
 <xsl:value-of select="r25:events/@pubdate"/>
</xsl:variable>

when you can do this:

<xsl:variable name="pubdate" select="r25:events/@pubdate"/>

The latter is not only one line of code instead of three, it's also much more efficient because it doesn't involve constructing a new tree.

(b) don't do this:

<xsl:element name="CALENDAR_ENTERPRISE">
 <xsl:attribute name="Created">
 <xsl:value-of select="$pubdate"/>
 </xsl:attribute>

when you can do this:

<CALENDAR_ENTERPRISE Created="{$pubdate}">

In Saxon it won't make any performance difference, but it's much more readable.

(c) I can't see why you are passing all these parameters. The values are all accessible from the context node, so I don't see why the called template can't get the values it needs by navigating from the context node.

answered Jun 30, 2012 at 23:51
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.