So I'm trying to create a variable and then later on use this in my template.
This is the code I have now:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="items">
<xsl:call-template name="item" />
</xsl:template>
<xsl:template name="item">
<xsl:for-each select="item">
<xsl:variable name="currentItemTheme">
test variable
</xsl:variable>
<xsl:if test="title = name">
Showvariable: {$currentItemTheme} <br/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I have no idea why it doesn't work. My file does output the "Showvariable: ", but it just doesn't show the test values. So the for-each loops and template aren't the problem.
Is there something I'm missing? Does someone know how I get this to work?
I think you want <xsl:value-of select="$currentItemTheme"/> instead of {$currentItemTheme}, unless you are mixing the XSLT code with some other language that provides the {$currentItemTheme} syntax.
<xsl:copy-of select="$currentItemTheme"/> is another option if you build nodes in your variable and want to output them instead of just the string value as a text node.
Related
I have an example document that looks like this
<document>
<memo>
<to>Allen</to>
<p>Hello! My name is <bold>Josh</bold></p>
<p>It's nice to meet you <bold>Allen</bold>. I hope that we get to meet up more often.</p>
<from>Josh</from>
<memo>
</document>
and this is my XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:company="http://my.company">
<xsl:output method="html"/>
<xsl:variable name="link" select="company:generate-link()"/>
<xsl:template match="/document/memo">
<h1>To: <xsl:value-of select="to"/></h1>
<xsl:for-each select="p">
<p><xsl:apply-templates select="node()" mode="paragraph"/></p>
</xsl:for-each>
<xsl:if test="from">
<p>From: <strong><xsl:value-of select="from"/></strong></p>
</xsl:if>
<xsl:copy-of select="$link"/>
</xsl:template>
<xsl:template match="bold" mode="paragraph">
<b><xsl:value-of select="."/></b>
</xsl:template>
<xsl:template match="text()" mode="paragraph">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
and the variable link contains the following example node:
When I do a copy-of out the variable link it prints out the node correctly (but obviously without any text). I want to insert it into the document and replace the text using XSLT. For example, the text could be:
View all of <xsl:value-of select="/document/memo/from"/>'s documents.
So the resulting document would look like:
<h1>To: Allen</h1>
<p>Hello! My name is <b>Josh</b></p>
<p>It's nice to meet you <b>Allen</b>. I hope that we get to meet up more often.</p>
<from>Josh</from>
View all of Josh's documents.
I have been searching the internet on how to do this but I couldn't find anything. If anyone could help I would appreciate it a lot!
Thanks,
David.
You haven't said which XSLT processor that is nor have you shown the code of that extension function to allow us to understand what it returns but based on your comment saying it returns a node you can usually process it further with templates so if you use <xsl:apply-templates select="$link"/> and then write a template
<xsl:template match="a[#href]">
<xsl:copy>
<xsl:copy-of select="#*"/>
View all of <xsl:value-of select="$main-doc/document/memo/from"/>'s documents.
</xsl:copy>
</xsl:template>
where you declare a global variable <xsl:variable name="main-doc" select="/"/> you should be able to transform the node returned from your function.
This is my XSLT file:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<xsl:for-each select="//child_4331">
<xsl:value-of select="*"/>
<xsl:value-of select="#value" />
<xsl:attribute name="onclick">
<xsl:call-template name="GetOnClickJavaScript" />
</xsl:attribute>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
How can I set the click event on child_4331 value?
You didn't say, but I'm assuming you want to copy the child_4331 element and add the onclick attribute.
I would get rid of the template matching '/' and create one to match 'child_4331'. Use xsl:copy to create a copy of the element and add the attribute inside it. If the child_4331 element has attributes or child elements you will want to use xsl:apply-templates to pick them up.
Here is a sample snippet. Your solution may vary depending on your desired output. I can't give you more without knowing what your source XML looks like and what you expect to see in the result.
<xsl:template match="child_4331">
<xsl:copy>
<xsl:attribute name="onclick">
<xsl:call-template name="GetOnClickJavaScript" />
</xsl:attribute>
</xsl:copy>
</xsl:template>
I have the following params defined in my xslt file:
<xsl:param name="language">E</xsl:param>
<xsl:param name="headerTitle-E">English Title</xsl:param>
<xsl:param name="headerTitle-F">French Title</xsl:param>
How do I display the appropriate header based on the language param?
This doesn't work:
<xsl:value-of select="concat('headerTitle','-',$language)" />
It outputs "headerTitle-E" as opposed to "English Title" (which is what I want).
I'm trying to find a clean solution for displaying the appropriate text based on the language parameter, without having to use a "choose" block for every bit of text.
Any ideas?
If you now where your parameters are, you can use a single XPath. For instance, try this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="language">F</xsl:param>
<xsl:param name="headerTitle-E">English Title</xsl:param>
<xsl:param name="headerTitle-F">French Title</xsl:param>
<xsl:template match="/">
<xsl:value-of select="document('')/*/
xsl:param[#name=concat('headerTitle-',$language)]"/>
</xsl:template>
</xsl:stylesheet>
However I think that this kind of task should be better accomplished making use of lookup tables than parameters.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:empo="lookup"
exclude-result-prefixes="empo"
version="1.0">
<xsl:param name="language">F</xsl:param>
<empo:header name="headerTitle-E">English Title</empo:header>
<empo:header name="headerTitle-F">French Title</empo:header>
<xsl:template match="/">
<xsl:value-of select="document('')/*/
empo:header[#name=concat('headerTitle-',$language)]"/>
</xsl:template>
</xsl:stylesheet>
You might also want use the current header as a variable, just use:
<xsl:variable name="Header" select="document('')/*/
empo:header[#name=concat('headerTitle-',$language)]"/>
You can use the full broadth of XSLT inside xsl:param and xsl:variable. So do it like this:
<xsl:variable name="headerTitle">
<xsl:choose>
<xsl:when test="$language = 'fr'">
French
</xsl:when>
<xsl:otherwise>
English
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="$headerTitle" />
Actually, the choose block is the clean solution, compared to creating dozens of unneeded variables.
Taking this question about beautiful XSL but getting more specific, how should I refactor this XSL to take advantage of apply-templates and/or keys.
I tend to "over use" for-each elements to control the context of the source and I can imagine that apply-templates can help. Despite much Google-ing, I still don't understand how to control context within the multiple templates.
In the below example, how can the repetitive XPath segments be reduced by refactoring?
<xsl:template match="/">
<xsl:element name="Body">
<xsl:element name="Person">
<xsl:if test="/source/dbSrc/srv/v[#name='name']/text()='false'">
<xsl:element name="PhoneNumber" />
<xsl:element name="Zip">
<xsl:value-of
select="/source/req[1]/personal-info/address-info/zip-code" />
</xsl:element>
</xsl:if>
<xsl:if test="/source/dbSrc/srv/v[#name='name']/text()='true'">
<xsl:element name="PhoneNumber" />
<xsl:element name="Zip">
<xsl:value-of select="/source/req[3]/personal-info/address-info/zip-code" />
</xsl:element>
</xsl:if>
</xsl:element>
</xsl:template>
One initial way of refactoring the given code would be the following:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<Body>
<Person>
<PhoneNumber/>
<Zip>
<xsl:apply-templates select=
"/*/dbSrc/srv/v[#name='name']"/>
</Zip>
</Person>
</Body>
</xsl:template>
<xsl:template match="v[#name='name' and .='true']">
<xsl:value-of select=
"/*/req[3]/personal-info/address-info/zip-code"/>
</xsl:template>
<xsl:template match="v[#name='name' and .='false']">
<xsl:value-of select=
"/*/req[1]/personal-info/address-info/zip-code"/>
</xsl:template>
</xsl:stylesheet>
Do note: The refactored code doesn't contain any conditional xslt instructions.
Further refactoring can let us get rid of the last too templates, because in this case additional templates aren't actually needed -- the code only creates a single element and depends on a single condition:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="vCond" select=
"/*/dbSrc/srv/v[#name='name']/text()='true'"/>
<xsl:variable name="vInd" select=
"3*$vCond + 1*not($vCond)"/>
<xsl:template match="/">
<Body>
<Person>
<PhoneNumber/>
<Zip>
<xsl:value-of select=
"/*/req[position()=$vInd]
/personal-info/address-info/zip-code"/>
</Zip>
</Person>
</Body>
</xsl:template>
</xsl:stylesheet>
Note: Here we assume that /*/dbSrc/srv/v[#name='name']/text() can have only two possible values: 'true' or 'false'
In XSLT 2.0 I would write this as:
<xsl:template match="/">
<Body>
<Person>
<PhoneNumber/>
<Zip>
<xsl:variable name="index" as="xs:integer"
select="if (/source/dbSrc/srv/v[#name='name']='true') then 3 else 1"/>
<xsl:value-of select="/source/req[$index]/personal-info/address-info/zip-code"/>
</Zip>
</Person>
</Body>
</xsl:template>
With 1.0, the xsl:variable becomes a bit more complicated but otherwise it's the same.
Note the use of literal result elements and variables to reduce the size of the code; also the avoidance of "/text()", which is nearly always bad practice.
There's very little mileage in using template rules here because you're using so little of the input data, and because you seem to know exactly where to find it. Template rules would come into their own if you wanted to be less rigid about knowing exactly where you are looking in the source: they help to make code more resilient to variability and change in the input. But without seeing the source and knowing more of the background, we can't tell you where that flexibility is needed. The hard-coding of the indexes "1" and "3" looks like a danger signal to me, but only you can judge that.
Hi is there away on how to declare a link(ie:http://www.google.com) as a variable and then using the variable for an else if?Something like this?
<xsl:element name="a">
<xsl:attribute name="href">http://www.google.com</xsl:attribute>// first get the link
<xsl:choose>
<xsl:when test="http://www.google.com">
Do something 1
</xsl:when>
<xsl:otherwise>
Do something 2
</xsl:choose>
</xsl:element>
Is this possible?What should i be looking at?
is there away on how to declare a
link(ie:http://www.google.com) as a
variable and then using the variable
for an else if?
Use this code as a working example -- of course you need to learn at least the basics of XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="vLink" select="'http://www.google.com'"/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="$vLink = 'http://www.google.com'">
It is the Google link...
</xsl:when>
<xsl:otherwise>
It is not (exactly) the Google link...
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on any XML document (not used), the wanted result is produced:
It is the Google link...
One can also use a global <xsl:param>. This can be set externally by the invoker of the transformation.
Match against the content straight forward, and declare the URL as a variable.
If you need it more globally try this:
...
<xsl:apply-templates select="a" />
...
<xsl:template match="a">
Just a link
</xsl:template>
<xsl:template match="a[starts-with(#href, 'http://google.com/') or starts-with(#href, 'http://www.google.com/')]">
Link to google.com
</xsl:template>
It's possible to some extent, but there is no if-else construct in XSL. Here's a version I tested that you might be able to adapt to your needs. The input I used was:
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<xml>
<LinkValue>http://www.google.com/</LinkValue>
</xml>
The XSL that showing "Do something 1" if LinkValue was the string above or "Do something 2" if I modified it was:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="LinkValue" select="//LinkValue"/>
<xsl:element name="a">
<xsl:attribute name="href"><xsl:value-of select="$LinkValue"/></xsl:attribute>
<xsl:if test="$LinkValue = 'http://www.google.com/'">
Do something 1
</xsl:if>
<xsl:if test="$LinkValue != 'http://www.google.com/'">
Do something 2
</xsl:if>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Hopefully you can use these samples to figure out exactly what you need to implement for your scenario.