how to check if a string variable is comma delimited in XSL? - html

I need to test if a xsl variable contains just one word or multiple comma separated words in xslt.
since the variable is dynamic, its a parameter that maps to url querystring which can either be sth like this:
index.aspx?role=manager
or
index.aspx?role=manager,director
in XSLT, i need to find out if the $role parameter is just one word or multiple comma separated words. If multiple words, then i need to extract each word and do xslt filtering based on those words like
/rows/row[role=extractedWord[1] or role = extractedWord[2]
so that only those rows matching for manager or director roles are returned.
Is this possible?
UPDATE:
I have a filter like this:
<xsl:variable name="AllPerRole" select="/dsQueryResponse/Rows/Row[contains(#EmployeeRoles,$Role)]" />
If role has just one value like index.aspx?role=manager then above works fine.
But if role is multiple words like these,
index.aspx?role=manager,director
then i need to some extract that string 'manager,CEO' and be able to do the following:
<xsl:variable name="AllPerRole" select="/dsQueryResponse/Rows/Row[contains(#EmployeeRoles,$Role{firstRole}) or contains(#EmployeeRoles,$Role{2ndRole})]" />

You can set up a variable for the first role in $Role as follows:
<xsl:variable name="Role1">
<xsl:choose>
<xsl:when test="contains($Role, ',')">
<xsl:value-of select="substring-before($Role, ',')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$Role" />
</xsl:otherwise>
<xsl:choose>
</xsl:variable>
And then set up a variable Role2 for the second role (if any), using substring-after() instead of substring-before().
Then:
<xsl:variable name="AllPerRole"
select="/dsQueryResponse/Rows/Row[
contains(#EmployeeRoles,$Role1) or contains(#EmployeeRoles,$Role2)]" />

Related

Cannot output a XSLT variable including "<"

Following XSLT code works:
<xsl:variable name="ret"> RET </xsl:variable>
<xsl:value-of select="$ret" disable-output-escaping="yes"/>
It outputs "RET". But this code does not work as expected:
<xsl:variable name="ret"> <RET/> </xsl:variable>
<xsl:value-of select="$ret" disable-output-escaping="yes"/>
I expect the output to be <RET/>.
I am doing this for the purpose of capturing output of "xsl:apply-templates" into a variable. The output of "xsl:apply-templates" may include HTML tags (e.g. blah,blah). I hope I can store the output into a variable and do some processing afterworlds.
The xsl:value-of instruction creates a text node. It does so by converting the selection to a string. Your variable contains an empty element that has no string-value - and converting it to a string results in an empty string.
To pass the variable contents to the output tree with no conversion, use the xsl:copy-of instruction.
P.S. In your original question you wrote:
I expect the output to be "<RET/>".
which indicates you thought the variable contains the string "<RET/>" that can be used to create an element by copying it to the output without escaping it. But in order to create such variable you would have to use:
<xsl:variable name="ret"><RET></xsl:variable>
And in any case, that's not a good way to create output.
Use xsl:copy-of instead of xsl:value-of.

XSLT New Line in CSV but not in the CSV

I hope this doesn't confuse you. I'm going to start from the perspective of an Excel file. If I add the word "Cat" to a cell and then use the key combination Alt+Enter I get a new line within the cell so then I can enter the word "Dog".
The outcome of this is that I have two lines within the one cell with Cat and Dog on the lines. I've written this in cell A2.
In A1 I wrote "Snake".
And in A3 I wrote "Hamster"
If I save this Excel file as CSV I get the following;
Snake
"CatDog"
Hamster
This is what I'm trying to achieve using XSLT.
But when I try this I do actually get a new line, like this;
Snake
"Cat
Dog"
Hamster
Which isn't what I'm after.
I'm receiving the data as a comma separated list from a different source (ie: not Excel).
Here is the XSLT code I'm trying to use at the moment;
<xsl:template name="parse-comma-separated">
<xsl:param name="text"/>
<xsl:param name="separator"/>
<xsl:choose>
<xsl:when test="not(contains($text, $separator))">
<xsl:value-of select="normalize-space($text)" />
</xsl:when>
<xsl:otherwise>
<xsl:text>
</xsl:text><xsl:value-of select="normalize-space(substring-before($text, $separator))" />
<xsl:call-template name="parse-comma-separated">
<xsl:with-param name="text" select="substring-after($text, $separator)"/>
<xsl:with-param name="separator" select="$separator"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
This appears to be putting a space between the Pets.
When I tried a straight up string-replace method (which works great if replacing commas with pipes) I actually get a new line which is kinda what I want but only in the cell, not a new line in the csv file.
Any and all help appreciated.

compare percentage values with xsl:choose

In XSL version 1.0 sheet I am populating a html table with percentage values from an xml. I would like to display the highlighted color of the percantages based on condition but the condition isn't processed as desired, therefore ignoring the condition in some way.
Relevant XSL:
<xsl:choose>
<xsl:when test="number(substring-before('diskspace','%')) > 80"><td bgcolor="red"><xsl:value-of select="diskspace"/></td></xsl:when>
<xsl:otherwise><td bgcolor="green"><xsl:value-of select="diskspace"/></td></xsl:otherwise>
</xsl:choose>
<xsl:choose>
<xsl:when test="number(substring-before('freeSwap','k')) < .1*number(substring-before('totalSwap','k'))"><td bgcolor="red"><xsl:value-of select="freeSwap"/></td></xsl:when>
<xsl:otherwise><td bgcolor="green"><xsl:value-of select="cpuUsage"/></td></xsl:otherwise>
</xsl:choose>
Is there something wrong with my test conditions? It is meant to convert the percentage value to a number to compare to another number.
Thanks in advance.
Suggestion from kjhughes led to fixing issue: "Take the quotes off of diskspace and freeSwap if they're intended to reference element values"

xslt need to select a single quote

i need to do this:
<xsl:with-param name="callme" select="'validateInput(this,'an');'"/>
I've read Escape single quote in xslt concat function and it tells me to replace ' with &apos; I've done that yet its still not working..
Does anyone know how do we fix this?:
<xsl:with-param name="callme" select="'validateInput(this,&apos;an&apos;);'"/>
Something simple that can be used in any version of XSLT:
<xsl:variable name="vApos">'</xsl:variable>
I am frequently using the same technique for specifying a quote:
<xsl:variable name="vQ">"</xsl:variable>
Then you can intersperse any of these variables into any text using the standard XPath function concat():
concat('This movie is named ', $vQ, 'Father', $vApos, 's secrets', $vQ)
So, this transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:variable name="vApos">'</xsl:variable>
<xsl:variable name="vQ">"</xsl:variable>
<xsl:template match="/">
<xsl:value-of select=
"concat('This movie is named ', $vQ, 'Father', $vApos, 's secrets', $vQ)
"/>
</xsl:template>
</xsl:stylesheet>
produces:
This movie is named "Father's secrets"
In XSLT 2.0 you can the character used as a string delimiter by doubling it, so
<xsl:with-param name="callme" select="'validateInput(this,''an'');'"/>
Another solution is to use variables:
<xsl:variable name="apos">'</xsl:variable>
<xsl:variable name="quot">"</xsl:variable>
<xsl:with-param name="callme" select="concat('validateInput(this,', $apos, 'an', $apos, ');')"/>
This is a little tricky, but you need to invert the apostrophe and quotes, like this:
<xsl:with-param name="callme" select='"validateInput(this,&apos;an&apos;);"' />
You're enclosing a string within one set of quotes, and the attribute value that contains it in another. In XSLT, which quotes you use are interchangeable in both cases, as long as you don't use the same one.
Previously, your &apos; was being parsed as the value of the match attribute was being read, and it was trying to set the value of the select to 'validateInput(this,'an');'. Although this is technically a valid string value, when XSLT processes it, it fails to parse it because it's tries to read it as a string literal, which is terminated prematurely before the an, as the same apostrophe is used there as was used to enclose the string.
Use " rather than &apos; (by using &apos; you are effectively nesting single quotation marks inside single quotation marks; you need to alternate single and double quotation marks as you nest, escaping as necessary).

Is there an elegant way to add multiple HTML classes with XSLT?

Let's say I'm transforming a multiple-choice quiz from an arbitrary XML format to HTML. Each choice will be represented as an HTML <li> tag in the result document. For each choice, I want to add an HTML class of correct to the <li> if that choice was the correct answer. Additionally, if that choice was the one selected by the user, I want to add a class of submitted to the <li>. Consequently, if the choice is the correct one as well as the submitted one, the <li> should have a class of correct submitted.
As far as I know, white-space separated attribute values aren't a part of the XML data model and thus cannot directly be created via XSLT. However, I have a feeling there's a better way of doing this than littering the code with one conditional for every possible combination of classes (which would be acceptable in this example, but unwieldy in more complex scenarios).
How can I solve this in an elegant way?
Example of Desired Result:
<p>Who trained Obi-Wan Kenobi?</p>
<ul>
<li>Mace Windu</li>
<li class="correct submitted">Qui-Gon Jinn</li>
<li>Ki-Adi-Mundi</li>
<li>Yaddle</li>
</ul>
Firstly, there is nothing wrong with whitespace in attribute values in XML: roughly speaking, attribute value normalization converts whitespace characters to spaces and collapses adjacent spaces to a single space when a document is parsed, but whitespace is definitely allowed. EDIT: See below for more on this.
Matthew Wilson's approach fails to include whitespace between the possible values, as you mention in your comment thereto. However, his approach is fundamentally sound. The final piece of the jigsaw is your dislike of redundant spaces: these can be eliminated by use of the normalize-space XPath function.
The following stylesheet puts all the bits together - note that it doesn't do anything with its input document, so for testing purposes you can run it against any XML document, or even against itself, to verify that the output meets your requirements.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="foo0" select="false()"/>
<xsl:variable name="bar0" select="true()"/>
<xsl:variable name="foo1" select="true()"/>
<xsl:variable name="bar1" select="false()"/>
<xsl:variable name="foo2" select="true()"/>
<xsl:variable name="bar2" select="true()"/>
<xsl:template match="/">
<xsl:variable name="foobar0">
<xsl:if test="$foo0"> foo</xsl:if>
<xsl:if test="$bar0"> bar</xsl:if>
</xsl:variable>
<xsl:variable name="foobar1">
<xsl:if test="$foo1"> foo</xsl:if>
<xsl:if test="$bar1"> bar</xsl:if>
</xsl:variable>
<xsl:variable name="foobar2">
<xsl:if test="$foo2"> foo</xsl:if>
<xsl:if test="$bar2"> bar</xsl:if>
</xsl:variable>
<li>
<xsl:attribute name="class">
<xsl:value-of select="normalize-space($foobar0)"/>
</xsl:attribute>
</li>
<li>
<xsl:attribute name="class">
<xsl:value-of select="normalize-space($foobar1)"/>
</xsl:attribute>
</li>
<li>
<xsl:attribute name="class">
<xsl:value-of select="normalize-space($foobar2)"/>
</xsl:attribute>
</li>
</xsl:template>
</xsl:stylesheet>
EDIT: Further to the question of spaces separating discrete components within the value of an attribute: The XML Spec defines a number of possible valid constructs as attribute types, including IDREFS and NMTOKENS. The first case matches the Names production, and the second case matches the NMTokens production; both these productions are defined as containing multiple values of the appropriate type, delimited by spaces. So space-delimited lists of values as the value of a single attribute are an inherent component of the XML information set.
Off the top of my head, you can build up a space-separated list with something like:
<li>
<xsl:attribute name="class">
<xsl:if cond="...">correct</xsl:if>
<xsl:if cond="...">submitted</xsl:if>
</xsl:attribute>
</li>
As far as I know, white-space separated attribute values aren't a part of the XML data model and thus cannot directly be created via XSLT
Unless you are converting to an XML language (which HTML is not, XHTML is), you shouldn't worry about the XML validity of the XSLT ouput. This can be anything, and doesn't need to conform to XML!