XSL transformation with link in variable name - xslt

I have the following XSL which I render into my HTML:
<xsl:for-each select="user">
<xsl:variable name="exampleurl">
<xsl:choose>
<xsl:when test="objecttype='2'">
Check this out: 
<strong><a class="link" href="http://www.example.com/beinspired">Inspiration</a></strong>.
</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="$exampleurl" />
</xsl:for-each>
However, when I print the variable $exampleurl only the text "Check this out: Inspiration." is printed. But the word "Inspiration" is not a clickable URL like I would want.
How to fix this?

value-of creates a text node, you want
<xsl:copy-of select="$exampleurl" />
(or of course in this case you don't need a variable at all, but I assume that's just the small example?

Related

XSL Sorting With Sitecore

I'm not very familiar with xsl, so I'm sort of stumbling my way though this.
My xsl file is building a menu. I am trying to sort the menu items by the value in menu title field in Sitecore. When I run the code, it does not sort. It just writes out each menu item four times.
Can anyone shed some light on what I am missing?
<xsl:template name="show-title">
<xsl:param name="root" />
<xsl:for-each select="$sc_currentitem/item">
<xsl:sort select="sc:fld('menu title',.)" order="ascending"/>
<xsl:choose>
<xsl:when test="sc:fld('menu title',$root)!=''">
<sc:text field="menu title" select="$root" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$root/#name" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
EDIT: Below is the data that the code above is generating
Example Output:
03/05/201203/05/201203/05/201203/05/2012
03/01/201203/01/201203/01/201203/01/2012
03/08/201203/08/201203/08/201203/08/2012
03/02/201203/02/201203/02/201203/02/2012
03/07/201203/07/201203/07/201203/07/2012
I am trying to get it to generate the following:
03/01/2012
03/02/2012
03/05/2012
03/07/2012
03/08/2012
Thanks!
It looks like you are trying to read menu title field from the wrong node. You should be reading it from context node --> . <--
Try this
<xsl:template name="show-title">
<xsl:param name="root" />
<xsl:for-each select="$sc_currentitem/item">
<xsl:sort select="sc:fld('menu title',.)" order="ascending"/>
<xsl:choose>
<xsl:when test="sc:fld('menu title',$root)!=''">
<sc:text field="menu title" select="." />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="./#name" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
This is just a guess as you don't really supply enough information for anyone to do more than guess but....
Within your for-each you are referring to $root e.g. <xsl:value-of select="$root/#name" />
I am guessing that the $root parameter contains a list of some kind and that you should be selecting just part of this list based on some value from the current for-each context

avoid mismatched tags outputting HTML with XSLT

I'm new to XSLT, and there's one specific thing I don't know how to do, despite hours of searching for the answer.
I'm outputting blocks of HTML (result sets), and sometimes the result is a hyperlink, sometimes it is not.
The simple flow looks like this:
<a...> if #url
some HTML code
</a> if #url
But if I do:
when #url
<a...>
/when
some HTML code
when #url
</a>
/when
... I'm told that I have mismatched tags.
I was using CDATA text for the anchor set, but a lot of messages say that this is a "hack" approach.
I'm trying to avoid having to repeat the entire HTML code block only to include the anchors on only one of them.
How do I do this?
-------edit / additional info-----------
Does this make more sense?
<xsl:template match="Row">
<xsl:choose>
<xsl:when test="#url!=''">
<a><xsl:attribute name="href"><xsl:value-of select="#url" /></xsl:attribute>
</xsl:when>
</xsl:choose>
<img />
<xsl:choose>
<xsl:when test="#url!=''">
</a>
</xsl:when>
</xsl:choose>
</xsl:template>
In XSLT, your output is a tree of nodes. Writing an element node is a single atomic operation; it can't be split into separate operations of writing a start tag and writing an end tag. You can't create half a node.
If you do try to treat <a> and </a> as separate and separable operations, you will get this error, because the stylesheet must be well-formed XML.
So, stand back and explain what you are trying to achieve, and then we can tell you how to achieve it properly in XSLT.
One way to refactor the XSLT to conditionally apply the hyperlink and not repeat the logic to produce the <img/> (or whatever more complex logic you are trying to avoid repeating) is to extract that logic out into a different template(s) as either a named template or a template with a #mode.
For instance:
<xsl:template match="Row">
<xsl:choose>
<xsl:when test="#url!=''">
<a>
<xsl:attribute name="href">
<xsl:value-of select="#url"/>
</xsl:attribute>
<xsl:apply-templates select="." mode="image"/>
</a>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="." mode="image"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!--The "common" logic to produce an image element, whether or not it will be surrounded by an anchor linking to the #url -->
<xsl:template match="Row" mode="image">
<img/>
</xsl:template>
An alternative way of accomplishing the same thing, but using templates instead of <xsl:choose>:
<xsl:template match="Row[#url]">
<a href="#url">
<xsl:apply-templates select="." mode="image"/>
</a>
</xsl:template>
<xsl:template match="Row">
<xsl:apply-templates select="." mode="image"/>
</xsl:template>
<xsl:template match="Row" mode="image">
<img/>
</xsl:template>

xsl:variable contains nodeset. How to output nth node of variable?

I am transforming an XML document. There is an attribute #prettydate that is a string similar to "Friday, May 7, 2010". I want to split that string and add links to the month and the year. I am using the exslt:strings module and I can add any other necessary EXSLT module.
This is my code so far:
<xsl:template match="//calendar">
<xsl:variable name="prettyparts">
<xsl:value-of select="str:split(#prettydate,', ')"/>
</xsl:variable>
<table class='day'>
<thead>
<caption><xsl:value-of select="$prettyparts[1]"/>,
<a>
<xsl:attribute name='href'><xsl:value-of select="$baseref"/>?date=<xsl:value-of select="#highlight"/>&per=m</xsl:attribute>
<xsl:value-of select='$prettyparts[2]'/>
</a>
<xsl:value-of select='$prettyparts[3]'/>,
<a>
<xsl:attribute name='href'><xsl:value-of select="$baseref"/>?date=<xsl:value-of select="#highlight"/>&per=y</xsl:attribute>
<xsl:value-of select='$prettyparts[4]'/>
</a>
</caption>
<!--etcetera-->
I have verified, by running $prettyparts through a <xml:for-each/> that I am getting the expected nodeset:
<token>Friday</token>
<token>May</token>
<token>7</token>
<token>2010</token>
But no matter which way I attempt to refer to a particular <token> directly (not in a foreach) I get nothing or various errors to do with invalid types. Here's some of the syntax I've tried:
<xsl:value-of select="$prettyparts[2]"/>
<xsl:value-of select="$prettyparts/token[2]"/>
<xsl:value-of select="exsl:node-set($prettyparts/token[2])"/>
<xsl:value-of select="exsl:node-set($prettyparts/token)[2]"/>
Any idea what the expression ought to be?
ETA: Thanks to #DevNull's suggestion, the correct expression is:
<xsl:value-of select="exsl:node-set($prettyparts)[position()=2]"/>
and, I have to set the variable this way:
<xsl:variable name="prettyparts" select="str:split(#prettydate,', ')" />
Try using [position()=2] instead of [2] in your predicates.
Example:
<xsl:value-of select="$prettyparts[position()=2]"/>

Display different xsl:attribute depending on the ending of a string

I have the following xsl code in an xsl document
<A target="_blank" style="text-decoration=none">
<xsl:attribute name="href">viewdoc.aspx?doc=<xsl:value-of select="URLFilePath"/>&mode=inline</xsl:attribute>
<xsl:attribute name="prefix"><xsl:value-of select="FileName"/>: </xsl:attribute>
<IMG src="images/word_small.gif" border="0"/>
</A>
and in the code-behind I am doing this
newItemNode = xmlDocument.CreateElement("URLFilePath")
newItemNode.InnerText = correctedPath
xmlItemNode.ParentNode.AppendChild(newItemNode)
Now that works fine for word documents. However I need a way in code to check the extension of the file, and display the correct Image and xsl:attribute depending on the If statement.
So the If statement will be like this:-
If correctedPath.ToLower.Contains(".doc") Then
//display the word icon and attributes
Else
//display the excel icon and attributes
End If
Can you please give me some tips and help on how I can achieve this?
Thanks
Just using contains() may generally produce the wrong results (see the test XML document).
What is necessary is a ends-with() function, which is standard in XPath 2.0 and can be implemented in XSLT 1.0 as in the following transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="URLFilePath">
<xsl:variable name="visDoc">
<xsl:call-template name="ends-with">
<xsl:with-param name="pEnding" select="'.doc'"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="visXls">
<xsl:call-template name="ends-with">
<xsl:with-param name="pEnding" select="'.xls'"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$visDoc=1">word_small.gif</xsl:when>
<xsl:when test="$visXls=1">xls_small.gif</xsl:when>
<xsl:otherwise>unknown_small.gif</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="ends-with">
<xsl:param name="pEnding"/>
<xsl:value-of select=
"number(substring(.,
string-length() -string-length($pEnding) +1
)
=
$pEnding
)
"/>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the following test XML document:
<files>
<URLFilePath>myFile.doc</URLFilePath>
<URLFilePath>myFile.xls</URLFilePath>
<URLFilePath>myFile.xls.doc</URLFilePath>
<URLFilePath>myFile.doc.xls</URLFilePath>
</files>
the correct result is produced:
word_small.gif
xls_small.gif
word_small.gif
xls_small.gif
Do note that just using contains() produces incorrect results.
I managed to come up with a solution! Sorry for the late reply but had to work on something else
Here is the code:-
<A target="_blank" style="text-decoration=none">
<xsl:choose>
<xsl:when test="contains(., '.doc')">
<xsl:attribute name="href">viewdoc.aspx?doc=<xsl:value-of select="URLFilePath"/>&mode=inline
</xsl:attribute>
<xsl:attribute name="prefix">
<xsl:value-of select="FileName"/>:
</xsl:attribute>
<IMG src="images/word_small.gif" border="0"/>
</xsl:when>
<xsl:when test="contains(., '.xls')">
<xsl:attribute name="href">viewxls.aspx?doc=<xsl:value-of select="URLFilePath"/>&mode=inline
</xsl:attribute>
<xsl:attribute name="prefix">
<xsl:value-of select="FileName"/>:
</xsl:attribute>
<IMG src="images/excel_small.gif" border="0"/>
</xsl:when>
</xsl:choose>
</A>
Thanks for all your help guys, really very much appreciated!
A late reply but I hit to two answers that deal with matching end of string with XSLT 1.0 and are very elegant:
https://stackoverflow.com/a/3081205/520567
https://stackoverflow.com/a/3081866/520567
go give them +1
This can be done purely in your XSLT document if you require. For displaying the image, you could use a xsl:choose statement, that tests the URLFilePath element
<xsl:choose>
<xsl:when test="contains(., '.doc')">
<IMG src="images/word_small.gif" border="0"/>
</xsl:when>
<xsl:when test="contains(., '.xls')">
<IMG src="images/excel_small.gif" border="0"/>
</xsl:when>
</xsl:choose>
If you wanted to do this check in the code behind, you could always add extra attributes to your URLFilePath element.
imageAttr = xmlDocument.CreateAttr("image")
If correctedPath.ToLower.Contains(".doc") Then
imageAttr.value = "images/word_small.gif"
Else
imageAttr.value = "images/excel_small.gif"
End If
newItemNode.AppendChild(imageAttr)
And then, in your xls, you can simply use this attribute to set the source attribute of the image
<IMG border="0">
<xsl:attribute name="src"><xsl:value-of select='#image' /></xsl:attribute>
</IMG>

XSLT: contains() for multiple strings

I have a variable in XSLT called variable_name which I am trying to set to 1, if the Product in question has attributes with name A or B or both A & B.
<xsl:variable name="variable_name">
<xsl:for-each select="product/attributes">
<xsl:if test="#attributename='A' or #attributename='B'">
<xsl:value-of select="1"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
Is there any way to match multiple strings using the if statement, as mine just matches if A is present or B is present. If both A & B are present, it does not set the variable to 1. Any help on this would be appreciated as I am a newbie in XSLT.
You can use xsl:choose statement, it's something like switch in common programming languages:
Example:
<xsl:variable name="variable_name">
<xsl:for-each select="product/attributes">
<xsl:choose>
<xsl:when test="#attributename='A'">
1
</xsl:when>
<xsl:when test=" #attributename='B'">
1
</xsl:when>
<!--... add other options here-->
<xsl:otherwise>1</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:variable>
This will set new variable with name variable_name with the value of attribute product/attributes.
For more info ... http://www.w3schools.comwww.w3schools.com/xsl/el_choose.asp
EDIT: And another way (a little dirty) by OP's request:
<xsl:variable name="variable_name">
<xsl:for-each select="product/attributes">
<xsl:if test="contains(text(), 'A') or contains(text(), 'B')">
1
</xsl:if>
</xsl:for-each>
</xsl:variable>
It will be helpful if you provide the xml you're writing your xslt against.
This might not help...
Is it 'legal' to have two XML element attributes with the same name (eg. <element x="1" x="2" />)?
Is this what you are trying to process? Try parsing your XML file through xmllint or something like it to see if it is valid.
xmllint --valid the-xml-file.xml
My guess is that you will get a 'attribute redefined' error.