I am looking at this xslt template:
<xsl:template match="row">
<xsl:param name="spans"/>
<xsl:param name="browserows"/>
<xsl:choose>
<xsl:when test="contains($spans, '0')">
<xsl:call-template name="normal-row">
<xsl:with-param name="spans" select="$spans"/>
<xsl:with-param name="browserows" select="$browserows"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
I am trying to understand where the value of $spans is coming from at the test statement on line 6, but it looks like the value was never assigned.
I cannot find spans as a global param anywhere.
Am I missing something?
It would come from the calling code that executed the <xsl:apply-templates> that matched against that row - because the <xsl:template> declares that parameter in <xsl:param name="spans"/>. If you didn't specify a value via <xsl:with-param>, then it is presumably nil.
Related
I have a parameterignoreAttributes which is a comma separated list of things to look for. I want to set a variable copyAttrib to be equal to whether any of them are exactly matched by name().
If xsl were a procedural language where variables could be reassigned, I'd use something like this:
<xsl:variable name="copyAttrib" select="true()">
<xsl:for-each select="tokenize($ignoreAttributes,',')">
<xsl:if test="compare(., name()) != 0">
<xsl:variable name="copyAttrib" select="false()"/>
</xsl:if>
</xsl:for-each>
Unfortunately, I can't do that, because xsl is functional (so says this other answer). So variables can only be assigned once.
I think the solution would look something like:
<vsl:variable name="copyAttrib">
<xsl:choose>
<xsl:when>
<xsl:for-each select="tokenize($ignoreAttributes, ',')">
<xsl:if test="compare(., name()) != 0"/>
</xsl:for-each>
<xsl:otherwise>
<xsl:value-of select="false()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
Obviously not exactly that (otherwise I wouldn't be asking.)
I know that I could bypass the tokenize and for-each loop by just using replaces on ignoreAttributes and changing all the , to | and then using matches, but I'd like to avoid that if possible because then I need to deal with the possibility that ignoreAttributes (which the user provides) might contain some special characters that will change the regex pattern and escape them all.
I have a parameterignoreAttributes which is a comma separated list of things to look for. I want to set a variable copyAttrib to be equal to whether any of them are exactly matched by name().
That sounds to me like
<xsl:variable name="copyAttrib" as="xs:boolean"
select="tokenize($parameterignoreAttributes, ',') = name()"/>
You say:
Unfortunately, I can't do that, because xsl is functional
when what you mean is: "Fortunately, I don't need to do that, because XSLT is functional".
An XSLT-1.0 way of doing this is by using a recursive, named template:
<xsl:template name="copyAttrib">
<xsl:param name="attribs" />
<xsl:choose>
<xsl:when test="normalize-space(substring-before($attribs,',')) = normalize-space(name(.))">
<xsl:value-of select="'true'" />
</xsl:when>
<xsl:when test="normalize-space($attribs) = ''">
<xsl:value-of select="'false'" />
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="copyAttrib">
<xsl:with-param name="attribs" select="substring-after($attribs,',')" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Apply this template onto the current, the selected, node and wrap it in a <xsl:variable>:
<xsl:variable name="copyAttribResult">
<xsl:call-template name="copyAttrib">
<xsl:with-param name="attribs" select="'a,b,c,...commaSeparatedValues...'" />
</xsl:call-template>
</xsl:variable>
to get either true or false as a result.
I have this following template which i am not sure correct or not
<xsl:template match="text()" name="createName">
<xsl:param name="Type"/>
<xsl:if test="contains(Type,'NEW')">
<xsl:value-of select="concat('New','Goal')"/>
</xsl:if>
<xsl:if test="contains(Type,'AMD')">
<xsl:value-of select="concat('Amended','Goal')"/>
</xsl:if>
</xsl:template>
Calling this template here
<xsl:element name="PackageName">
<xsl:call-template name="createName">
<xsl:with-param name="Type" select="s0:PIXField/s0:TransactionID"/>
</xsl:call-template>
</xsl:element>
s0:PIXField/s0:TransactionID = BPA201605311506452806320060A1AMD
I want to create PackageName element with value 'Amended Goal'.
But for now i am getting empty PackageName. dont know where my code fails.
Please help.
If you want to access a parameter, you need to use the $ prefix. That is to say, do contains($Type,'NEW') and not contains(Type,'NEW'). The latter is looking for a child element called Type, and not the passed in parameter
Try this template. Note that you don't really need to use xsl:value-of with concat to output the text.
<xsl:template match="text()" name="createName">
<xsl:param name="Type"/>
<xsl:if test="contains($Type,'NEW')">
<xsl:text>New Goal</xsl:text>
</xsl:if>
<xsl:if test="contains($Type,'AMD')">
<xsl:text>Amended Goal</xsl:text>
</xsl:if>
</xsl:template>
Also note, you may not actually need the match attribute on the template either, if the template is only ever being called as a named template.
Also consider using xsl:choose / xsl:when instead of xsl:if.
You call this template in exactly the same way as shown in your question
<xsl:element name="PackageName">
<xsl:call-template name="createName">
<xsl:with-param name="Type" select="s0:PIXField/s0:TransactionID"/>
</xsl:call-template>
</xsl:element>
Nothing changes there at all.
In the following piece of code, I want to understand what is "$type" here and how it is being used.
How this if condition is being applied using "$type".
<xsl:template name="CodValue">
<xsl:param name="type"/>
<xsl:param name="nodeNM">category</xsl:param>
<xsl:element name="{$nodeNM}">
<xsl:if test="$type">
<xsl:attribute name="xsi:type">
<xsl:value-of select="$type"/>
</xsl:attribute>
</xsl:if>
</xsl:element>
</xsl:template>
For this template, you need a parameter, another one is optional nodeNM. You can call the parameter like this:
<xsl:call-template name="CodValue">
<xsl:with-param name="type" select="123" />
</xsl:call-template>
or
<xsl:call-template name="CodValue">
<xsl:with-param name="type">123</xsl:with-param>
</xsl:call-template>
type is a variable in CodValue, so you can print it via
<xsl:value-of select="$type" />
or via {$type} in attributes.
Suggestions:
$nodeNM looks like the name of a tag (html-tags if you produce HTML-Code).
$type (if returns true from xpath, ie. if not empty) will create a xsi:type-Tag-Attribute.
So if you call
<xsl:call-template name="CodValue">
<xsl:with-param name="type" select="123" />
</xsl:call-template>
Your XML will be transformed into
<category xsi:type="123" />
$ is used to reference a variable inside an XPath expression.
In this particular case, $type is declared earlier by <xsl:param name="type"/>. However, it has not been given a value so you will need to use <xsl:with-param> when calling the template to so that you can provide a value.
n.b. The variable $nodeNM was given a default value, so you don't need to specify that when calling the template.
So,
I have an XSLT template which expects a node set as a parameter and uses this as display text. However, sometimes this node is empty in the XML and I want to pass default display text instead of the display text not showing up instead:
Works:
<xsl:call-template name="myTemplate">
<xsl:with-param name="parm1" select="//element">
</xsl:call-template>
Doesn't work:
<xsl:variable name="dispText">
<xsl:choose>
<xsl:when test="string-length(//element) = 0">
<xsl:value-of select="'Default Text'" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="//element" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:call-template name="myTemplate">
<xsl:with-param name="parm1" select="$dispText">
</xsl:call-template>
Any ideas as to how I could accomplish this? I've tried all sorts of things with no luck :(
It seems like all I need to do is create a new node with the display text I want, but I don't know if that is even possible?
Thanks
Implement the default handling in the template, because that's where it belongs. The calling side should be consistent and not have side-effects on the template behavior (i.e. you should not be able to "forget" passing in the default value).
<xsl:template name="myTemplate">
<xsl:param name="parm1" /><!-- node set expected! -->
<!-- actual value or default -->
<xsl:variable name="value1">
<xsl:choose>
<xsl:when test="not($parm1 = '')">
<xsl:value-of select="$parm1" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$default1" />
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<!-- work with $value1 from this point on -->
</xsl:template>
I'm guessing //element is a nodeset and using string-length() on it might not be valid. Try converting it to a string() first?
I'd like to apply a template with different parameters based on the result of a conditional. Something like this:
<xsl:choose>
<xsl:when test="#attribute1">
<xsl:apply-templates select='.' mode='custom_template'>
<xsl:with-param name="attribute_name" tunnel="yes">Attribute no. 1</xsl:with-param>
<xsl:with-param name="attribute_value" tunnel="yes"><xsl:value-of select="#attribute1"/></xsl:with-param>
</xsl:apply-templates>
</xsl:when>
<xsl:when test="#attribute2">
<xsl:apply-templates select='.' mode='custom_template'>
<xsl:with-param name="attribute_name" tunnel="yes">Attribute no. 2</xsl:with-param>
<xsl:with-param name="attribute_value" tunnel="yes"><xsl:value-of select="#attribute1"/></xsl:with-param>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select='.' mode='custom_template'>
<xsl:with-param name="attribute_name" tunnel="yes">Error</xsl:with-param>
<xsl:with-param name="attribute_value" tunnel="yes">No matching attribute </xsl:with-param>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
First of all, I suspect that this could be resolved in a much, much better way. (I'm entirely new to XSLT, so please suggest improvements and forgive the bloated code.)
Now for the question: how could I've set the parameters based on this conditional, and still used them in an xsl:apply-templates? I've tried to wrap the entire xsl:choose with a xsl:apply-templates start-/end-tag, but that's apparently not legal. Any clues?
An alternate method would be to put the xsl:choose statements within the xsl:param elements
<xsl:apply-templates select="." mode="custom_template">
<xsl:with-param name="attribute_name" tunnel="yes">
<xsl:choose>
<xsl:when test="#attribute1">Attribute no. 1</xsl:when>
<xsl:when test="#attribute2">Attribute no. 2</xsl:when>
<xsl:otherwise>Error</xsl:otherwise>
</xsl:choose>
</xsl:with-param>
<xsl:with-param name="attribute_value" tunnel="yes">
<xsl:choose>
<xsl:when test="#attribute1"><xsl:value-of select="#attribute1"/></xsl:when>
<xsl:when test="#attribute2"><xsl:value-of select="#attribute1"/></xsl:when>
<xsl:otherwise>No matching attribute </xsl:otherwise>
</xsl:choose>
</xsl:with-param>
</xsl:apply-templates>
Nothing wrong with your method, but you can also append your conditional into xsl:template match attribute. This will lead to just one xsl:apply-templates, but several xsl:template elements
You can get rid of all that logic and the modes by extracting your conditions into predicates. You don't say what the name of the element you're dealing with is, but assuming it's called foo then something like this should suffice:
<xsl:template match="foo[#attribute1]">
<!--
do stuff for the case when attribute1 is present
(and does not evaluate to false)
-->
</xsl:template>
<xsl:template match="foo[#attribute2]">
<!--
do stuff for the case when attribute2 is present
(and does not evaluate to false)
-->
</xsl:template>
<xsl:template match="foo">
<!--
do stuff for the general case
(when neither attribute1 nor attribute 2 are present)
-->
</xsl:template>