XSLT foreach - xslt

Hi i have a strange issue with matching specific attribute of xml node.
Example code that doesnt work:
<xsl:for-each select="../../unit/service/price/season[#name=$period_name]">
<xsl:attribute name="std_bed_price">
<xsl:value-of select="../#amount"/>
</xsl:attribute>
</xsl:for-each>
Example code that DOES work but i don't like this way too much:
<xsl:for-each select="../../unit/service/price/season">
<xsl:if test="#name = $period_name">
<xsl:attribute name="std_bed_price">
<xsl:value-of select="../#amount"/>
</xsl:attribute>
</xsl:if>
</xsl:for-each>
If in first example i replace the variable name with some of the values like 'A' it works,
i also tested what variable name is selected and it has the correct data inside (so, 'A','B','C' ...)
Anyone had this problem before?
Tnx

You might try changing it to an apply-templates instead of a foreach. Something like the following should work.
<xsl:template match="price">
<xsl:attribute name="std_bed_price">
<xsl:value-of select="#amount" />
</xsl:attribute>
</xsl:template>
And then call it like:
<xsl:apply-template select="../../unit/service/price/[season/#name=$period_name]" />

Not seen this before. Could it be an ambiguous #name attribute. Therefore try accessing it like below?
select="../../unit/service/price/season[./#name=$period_name]
Other than that, sorry, to me it looks like it should work perfectly both ways.

Related

XSL transformation with link in variable name

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?

Can this XSLT snippet be more concise?

In the following code snippet, I have 3 for-each's but it seems to me they ought to be able to combine into one. It works as is, but I was wondering if anyone knew of a more elegant way to write it?
<xsl:for-each select="/essentials/webservice">
<xsl:for-each select="document(#filename)/productSearchResponse/products/product">
<xsl:sort select="producingRegion" order="ascending"/>
<xsl:for-each select="producingRegion[not(preceding::producingRegion=.)]">
<xsl:value-of select="."/>
<br/>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
It's hard to give an answer without knowing the expected result and structure of the input XML, but I believe this should work.
<xsl:for-each select="/essentials/webservice">
<xsl:for-each select="document(#filename)/productSearchResponse/products/product/producingRegion[not(preceding::producingRegion=.)]">
<xsl:value-of select="."/>
<br/>
</xsl:for-each>
</xsl:for-each>
Edit: I just noticed that document(#filename) is a function call, not a node test. In that case, I think you need two for-eaches.
You can make it a little more concise by using a double slash in the XPath expression, though I tend to think that's not a very good practice:
<xsl:for-each select="/essentials/webservice">
<xsl:for-each select="document(#filename)//producingRegion[not(preceding::producingRegion=.)]">
<xsl:value-of select="."/>
<br/>
</xsl:for-each>
</xsl:for-each>

Can you use <xsl:for-each> to go through attributes?

Is it possible to use the command on attributes? I want this to be able to run without knowing the attribute names. Here's a quick (terrible) example:
<candy hard="true" soft="false" stripes="true" solid="false">
In my head (this doesn't work) it should look something like this:
<xsl:for-each select="candy/#[#='true']">
Is there a way around this to run through attributes without knowing their name, or do I need to write each attribute being looked at?
Edit
Heres an example of me trying to create a variable out of the attribute name where value='true'
<xsl:for-each select="candy/#*[. = 'true']">
<xsl:attribute name="candytype">
<xsl:value-of select="name()"/>
</xsl:attribute>
<xsl:text> </xsl:text>
<xsl:for-each>
OP's comment:
can I return each attribute name (not value) whose value='true'?
<xsl:for-each select="candy/#*[. = 'true']">
<xsl:value-of select="name()"/>
<xsl:text> </xsl:text>
<xsl:for-each>
In XSLT 2.0 simply evaluate this XPath (2.0) expression:
candy/#*[. = 'true']/concat(name(.), ' ')
What you want is
<xsl:for-each select="candy/#*">

XSLT for-each counter - how to access data

for performance testing purposes I want to take a small XML file and create a bigger one from it - using XSLT. Here I plan to take each entity (Campaign node in the example below) in the original XML and copy it n times, just changing its ID.
The only way I can think of to realize this, is a xsl:for-each select "1 to n". But when I do this I do not seem to be able to access the entity node anymore (xsl:for-each select="campaigns/campaign" does not work in my case). I am getting a processor error: "cannot be used here: the context item is an atomic value".
It seems that by using the "1 to n" loop, I am loosing the access to my actual entity. Is there any XPath expression that gets me access back or does anyone have a completely different idea how to realize this?
Here is what I do:
Original XML
<campaigns>
<campaign id="1" name="test">
<campaign id="2" name="another name">
</cmpaigns>
XSLT I try to use
<xsl:template match="/">
<xsl:element name="campaigns">
<xsl:for-each select="1 to 10">
<xsl:for-each select="campaigns/campaign">
<xsl:element name="campaign">
<xsl:copy-of select="#*[local-name() != 'id']" />
<xsl:attribute name="id"><xsl:value-of select="#id" /></xsl:attribute>
</xsl:element>
</xsl:for-each>
</xsl:for-each>
</xsl:element>
</xsl:template>
Define a variable as the first thing in the match, like so:
<xsl:variable name="foo" select="."/>
This defines a variable $foo of type nodeset. Then access it like this
<xsl:for-each select="$foo/campaigns/campaign">
...
</xsl:for-each>

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]"/>