Page 1 of 1

Apply-templates with-param problem / question

Posted: Fri Jan 11, 2008 12:11 am
by Stefan Messmer
Hi all,
I observed a problem that seems to be a little strange. I defined a variable "date" with the following content:
<Cluster Name="Time stamp" NumElts="10">
<DBL Name="fractional second">0.13610</DBL>
<I32 Name="second">4</I32>
<I32 Name="minute">21</I32>
<I32 Name="hour">11</I32>
<I32 Name="day of month">4</I32>
<I32 Name="month">4</I32>
<I32 Name="year">2007</I32>
<I32 Name="day of week">4</I32>
<I32 Name="day of year">94</I32>
<I32 Name="DST">1</I32>
</Cluster>
The variable therefore contains a node set. Then I applied a template the following way:
<xsl:apply-template match=".">
<xsl:with-param name="my-date" select="$date"/>
</xsl:apply-template>

The template should replace an element <date/> with the actual date. The template looks the following:
<xsl:template match="date">
<xsl:param name="my-date"/>
.....
.....
</xsl:template>

Now the problem: Saxon 6.5, Xalan, Firefox, Opera will return an error, because the content of the variable my-date is a string and not a node set. Safari (xslt.lib) and Saxon 9 process this code as expected.

Which behavior is correct? Does anybody know a workaround?

Thanks for your help
Stefan Messmer

Posted: Fri Jan 11, 2008 3:46 pm
by Dan
How did you defined the variable?
In the stylesheet, like the following, or it was given as a parameter to the XSLT processor?

Code: Select all

 
<xsl:variable name="date">
<Cluster Name="Time stamp" NumElts="10">
<DBL Name="fractional second">0.13610</DBL>
<I32 Name="second">4</I32>
<I32 Name="minute">21</I32>
<I32 Name="hour">11</I32>
<I32 Name="day of month">4</I32>
<I32 Name="month">4</I32>
<I32 Name="year">2007</I32>
<I32 Name="day of week">4</I32>
<I32 Name="day of year">94</I32>
<I32 Name="DST">1</I32>
</Cluster>
</xsl:variable>
I have tried this and worked correctly:

Code: Select all


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>

<xsl:variable name="date">
<Cluster Name="Time stamp" NumElts="10">
<DBL Name="fractional second">0.13610</DBL>
<I32 Name="second">4</I32>
<I32 Name="minute">21</I32>
<I32 Name="hour">11</I32>
<I32 Name="day of month">4</I32>
<I32 Name="month">4</I32>
<I32 Name="year">2007</I32>
<I32 Name="day of week">4</I32>
<I32 Name="day of year">94</I32>
<I32 Name="DST">1</I32>
</Cluster>
</xsl:variable>


<xsl:template match="/">
<xsl:apply-templates select="//date">
<xsl:with-param name="my-date" select="$date"/>
</xsl:apply-templates>
</xsl:template>

<xsl:template match="date">
<xsl:param name="my-date"/>
<out>
<xsl:copy-of select="$my-date"/>
</out>
</xsl:template>

</xsl:stylesheet>
Can you give a complete sample? XSL, XML input, parameters?

Cheers,
Dan

Posted: Fri Jan 11, 2008 6:53 pm
by jkmyoung
Saxon 9 is a XSLT 2.0 processor is it not?
As such it would probably ignore these errors.

The behaviour that is correct is throwing the error.

If you're looking for compatibility, why not use the exsl:node-set extension?

Code: Select all


xmlns:exsl="http://exslt.org/common"
...
<xsl:with-param name="my-date" select="exsl:node-set($date)"/>
Another work-around. Encase in wrapper and use document function to retrieve.
The select attribute xpath ensures that these are treated as actual nodes.

Code: Select all


<my:mapping xmlns:my="internal">
<Cluster Name="Time stamp" NumElts="10">
<DBL Name="fractional second">0.13610</DBL>
<I32 Name="second">4</I32>
<I32 Name="minute">21</I32>
<I32 Name="hour">11</I32>
<I32 Name="day of month">4</I32>
<I32 Name="month">4</I32>
<I32 Name="year">2007</I32>
<I32 Name="day of week">4</I32>
<I32 Name="day of year">94</I32>
<I32 Name="DST">1</I32>
</Cluster>
</my:mapping>

<xsl:variable name="date" select="document('')//Cluster"/>

Posted: Fri Jan 11, 2008 6:55 pm
by jkmyoung
For further clarifications, the exsl namespace will work in saxon, not IE, and I don't know about firefox and opera.

(annoying that you can't edit posts)

Posted: Fri Jan 11, 2008 9:58 pm
by Stefan Messmer
Hi all

I have prepared an example. It should demonstrate my problem and it should be simple enough to understand quickly. First of all, the xml file:

Code: Select all


<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test.xsl" ?>
<data>
<Cluster Name="test-date" NumElts="10">
<DBL Name="fractional second">0.13610</DBL>
<I32 Name="second">4</I32>
<I32 Name="minute">21</I32>
<I32 Name="hour">11</I32>
<I32 Name="day of month">4</I32>
<I32 Name="month">4</I32>
<I32 Name="year">2007</I32>
<I32 Name="day of week">4</I32>
<I32 Name="day of year">94</I32>
<I32 Name="DST">1</I32>
</Cluster>
<String Name="rope-name">Zugseil</String>
<String Name="test-advice">Seilverordnung</String>
<String Name="installation-name-nickname">Musteranlage</String>
<Section Name="section-1" Printflag="true">
<Textblock Name="Entspricht Seilverordnung">Das <rope-name/> der Anlage
<installation-name-nickname/> entsprach zum Zeitpunkt der Prüfung am <test-date
format="short"/> in den geprüften Bereichen den Anforderungen der
<test-advice/>.</Textblock>
<Section Name="subsection-11" Printflag="true">
<Textblock Name="Entspricht Seilverordnung">Das <rope-name/> der Anlage
<installation-name-nickname/> entsprach zum Zeitpunkt der Prüfung am <test-date
format="abbreviated"/> in den geprüften Bereichen den Anforderungen der
<test-advice/>.</Textblock>
<Textblock Name="Entspricht Seilverordnung">Das <rope-name/> der Anlage
<installation-name-nickname/> entsprach zum Zeitpunkt der Prüfung am <test-date
format="long"/> in den geprüften Bereichen den Anforderungen der
<test-advice/>.</Textblock>
</Section>
<Textblock Name="Entspricht Seilverordnung">Das <rope-name/> der Anlage
<installation-name-nickname/> entsprach zum Zeitpunkt der Prüfung am <test-date
format="short"/> in den geprüften Bereichen den Anforderungen der
<test-advice/>.</Textblock>
</Section>
</data>
The corresponding stylesheet is as follows:

Code: Select all


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="data">
<xsl:variable name="test-date" select="Cluster[@Name='test-date']"/>
<xsl:variable name="test-advice" select="String[@Name='test-advice']"/>
<xsl:variable name="rope-name" select="String[@Name='rope-name']"/>
<xsl:variable name="installation-name-nickname" select="String[@Name='installation-name-nickname']"/>
<htmL>
<title>Report</title>
<body>
<xsl:for-each select="//Textblock"><p>
<xsl:apply-templates select=".">
<xsl:with-param name="my-date" select="$test-date"/>
<xsl:with-param name="my-advice" select="$test-advice"/>
<xsl:with-param name="my-rope-name" select="$rope-name"></xsl:with-param>
<xsl:with-param name="my-installation-name" select="$installation-name-nickname"></xsl:with-param>
</xsl:apply-templates></p>
</xsl:for-each>
</body>
</htmL>
</xsl:template>
<xsl:template match="test-advice">
<xsl:param name="my-advice"/>
<xsl:value-of select="$my-advice"/>
</xsl:template>
<xsl:template match="rope-name">
<xsl:param name="my-rope-name"/>
<xsl:value-of select="$my-rope-name"/>
</xsl:template>
<xsl:template match="installation-name-nickname">
<xsl:param name="my-installation-name"/>
<xsl:value-of select="$my-installation-name"/>
</xsl:template>
<xsl:template match="test-date">
<xsl:param name="my-date"/>
<xsl:variable name="format" select="@format"/>
<xsl:choose>
<xsl:when test="$format = 'short'">
<xsl:value-of select="$my-date/I32[@Name='day of month']"/>.<xsl:value-of
select="$my-date/I32[@Name='month']"/>.<xsl:value-of
select="$my-date/I32[@Name='year']"/>
</xsl:when>
<xsl:when test="$format = 'abbreviated'">
<xsl:value-of select="$my-date/I32[@Name='day of month']"/>.<xsl:choose>
<xsl:when test="$my-date/I32[@Name='month']=1"> Jan </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=2"> Feb </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=3"> Mar </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=4"> Apr </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=5"> Mai </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=6"> Jun </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=7"> Jul </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=8"> Aug </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=9"> Sep </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=10"> Okt </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=11"> Nov </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=12"> Dez </xsl:when>
<xsl:otherwise>(Fehler im Datum)</xsl:otherwise>
</xsl:choose><xsl:value-of select="$my-date/I32[@Name='year']"/>
</xsl:when>
<xsl:when test="$format = 'long'">
<xsl:value-of select="$my-date/I32[@Name='day of month']"/>.<xsl:choose>
<xsl:when test="$my-date/I32[@Name='month']=1"> Januar </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=2"> Februar </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=3"> März </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=4"> April </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=5"> Mai </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=6"> Juni </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=7"> Juli </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=8"> August </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=9"> September </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=10"> Oktober </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=11"> November </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=12"> Dezember </xsl:when>
<xsl:otherwise>(Fehler im Datum)</xsl:otherwise>
</xsl:choose><xsl:value-of select="$my-date/I32[@Name='year']"/>
</xsl:when>
<xsl:otherwise>(Nicht unterstütztes Format "<xsl:value-of select="$format"
/>")</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
I hope this helps to clarify the problem.

Best regards
Stefan Messmer[/code]

Posted: Mon Jan 14, 2008 1:55 pm
by Dan
Changing the stylesheet version to "1.1" and changing the apply-templates select value from "." to "./*" seems to fix the problem when using Saxon 6, Xalan, Firefox (I have not tested IE and Opera):

Code: Select all


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.1">
........
<xsl:apply-templates select="./*">
More reading about the node-sets here:http://www.xml.com/pub/a/2003/07/16/nodeset.html

Posted: Mon Jan 14, 2008 7:11 pm
by Stefan Messmer
Hi all,

I found another solution. The stylesheet is attached below. :D

Many thanks for your help
Stefan Messmer

Code: Select all

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="data">
<xsl:variable name="test-date" select="Cluster[@Name='test-date']"/>
<xsl:variable name="test-advice" select="String[@Name='test-advice']"/>
<xsl:variable name="rope-name" select="String[@Name='rope-name']"/>
<xsl:variable name="installation-name-nickname"
select="String[@Name='installation-name-nickname']"/>
<html>
<title>Report</title>
<body>
<xsl:for-each select="//Textblock">
<p>
<xsl:apply-templates>
<xsl:with-param name="my-date" select="$test-date"/>
<xsl:with-param name="my-advice" select="$test-advice"/>
<xsl:with-param name="my-rope-name" select="$rope-name"/>
<xsl:with-param name="my-installation-name" select="$installation-name-nickname"/>
</xsl:apply-templates>
</p>
</xsl:for-each>
</body>
</html>
</xsl:template>
<xsl:template match="test-advice">
<xsl:param name="my-advice"/>
<xsl:value-of select="$my-advice"/>
</xsl:template>
<xsl:template match="rope-name">
<xsl:param name="my-rope-name"/>
<xsl:value-of select="$my-rope-name"/>
</xsl:template>
<xsl:template match="installation-name-nickname">
<xsl:param name="my-installation-name"/>
<xsl:value-of select="$my-installation-name"/>
</xsl:template>
<xsl:template match="test-date">
<xsl:param name="my-date"/>
<xsl:variable name="format" select="@format"/>
<xsl:choose>
<xsl:when test="$format = 'short'">
<xsl:value-of select="$my-date/I32[@Name='day of month']"/>.<xsl:value-of
select="$my-date/I32[@Name='month']"/>.<xsl:value-of select="$my-date/I32[@Name='year']"/>
</xsl:when>
<xsl:when test="$format = 'abbreviated'">
<xsl:value-of select="$my-date/I32[@Name='day of month']"/>.<xsl:choose>
<xsl:when test="$my-date/I32[@Name='month']=1"> Jan </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=2"> Feb </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=3"> Mar </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=4"> Apr </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=5"> Mai </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=6"> Jun </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=7"> Jul </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=8"> Aug </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=9"> Sep </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=10"> Okt </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=11"> Nov </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=12"> Dez </xsl:when>
<xsl:otherwise>(Fehler im Datum)</xsl:otherwise>
</xsl:choose><xsl:value-of select="$my-date/I32[@Name='year']"/>
</xsl:when>
<xsl:when test="$format = 'long'">
<xsl:value-of select="$my-date/I32[@Name='day of month']"/>.<xsl:choose>
<xsl:when test="$my-date/I32[@Name='month']=1"> Januar </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=2"> Februar </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=3"> März </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=4"> April </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=5"> Mai </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=6"> Juni </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=7"> Juli </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=8"> August </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=9"> September </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=10"> Oktober </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=11"> November </xsl:when>
<xsl:when test="$my-date/I32[@Name='month']=12"> Dezember </xsl:when>
<xsl:otherwise>(Fehler im Datum)</xsl:otherwise>
</xsl:choose><xsl:value-of select="$my-date/I32[@Name='year']"/>
</xsl:when>
<xsl:otherwise>(Nicht unterstütztes Format "<xsl:value-of select="$format"
/>")</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>

Posted: Mon Jan 14, 2008 8:01 pm
by jkmyoung
Another alternative to wieldly nested choose clauses is this little trick:

<my:mapping xmlns:my="internal">
<month short="1" abr="Jan" long="Januar" />
<month short="2" abr="Feb" long="Februar" />
<month short="3" abr="Mar" long="März" />
<month short="4" abr="Apr" long="April" />
<month short="5" abr="Mai" long="Mai" />
<month short="6" abr="Jun" long="Juni" />
<month short="7" abr="Jul" long="Juli" />
<month short="8" abr="Aug" long="August" />
<month short="9" abr="Sep" long="September" />
<month short="10" abr="Okt" long="Oktober" />
<month short="11" abr="Nov" long="November" />
<month short="12" abr="Dez" long="Dezember" />
</my:mapping>
<xsl:variable name="monthNum" select="$my-date/I32[@Name='month']"/>

Then in your abbreviated choose clause could have something like
<xsl:value-of select="document('')//month[@short=$monthNum]/@abr"/>

long choose clause:
<xsl:value-of select="document('')//month[@short=$monthNum]/@long"/>

This may be of use to you.