copying node and replace value in XSLT - xslt

I want to copy and replace a value in xlst but i get a blank value
<xsl:template match="/Tests/test/comment">
<xsl:copy>
<xsl:value-of select="NEW"/>
</xsl:copy>
</xsl:template>
I get
<comment></comment>
i want
<comment>NEW</comment>

value-of takes a value of a node named NEW in the current context. I don't think this is that you meant to do.
Try
<xsl:template match="/Tests/test/comment">
<xsl:copy>NEW</xsl:copy>
</xsl:template>

Put your word NEW in single quotes like this:
<xsl:value-of select="'NEW'"/>

Related

Create new element with fixed value and dynamic attribute using xslt

if i'm trying to understand xslt where i'm stuck at a place where i want to add an element with a fixed value and a dynamic attribute
input:
<newsItem parentGUID="fakeGuid">
</newsItem>
desired output:
<newsItem>
<parent Key="fakeGuid">News</parent>
<newsItem>
Current Xslt (value isn't in the actual output)
<xsl:template match="NewsItem">
<xsl:element name="Parent">
<xsl:attribute name="Key">
<xsl:value-of select="#parentGUID"/>
</xsl:attribute>
<xsl:value-of select="News"/>
</xsl:element>
</xsl:template>
Can someone point me out what i'm doing wrong?
Kind regards
The instruction:
<xsl:value-of select="News"/>
looks for a child element named News to extract its string-value. To output the literal text "News", try:
<xsl:text>News</xsl:text>
Note also that you don't need to use xsl:element to create a literal result element. To get the result you show, you could do:
<xsl:template match="newsItem">
<xsl:copy>
<Parent key="{#parentGUID}">News</Parent>
</xsl:copy>
</xsl:template>
Read about attribute value templates to understand how this works.

Excluding a single element in XSLT when using document()

I'm using document() to copy the content of an XML file (tagged for DITA) into a variable. Here is the code I had used previously that worked:
<xsl:variable name="fileContent">
<xsl:copy-of select="document($fileSrc)"/>
</xsl:variable>
Now, I want to include everything except the <draft-comment> element. I've tried to change document() as follows:
<xsl:variable name="fileContent">
<xsl:copy-of select="document($fileSrc)/*[not(draft-comment)]"/>
</xsl:variable>
This doesn't seem to work. The text is still there. Any suggestions on how I can fix this? Thank you for your help.
Create two templates with the mode attribute; one to copy nodes unchanged, and one to ignore draft-comment
<xsl:template match="#*|node()" mode="document">
<xsl:copy>
<xsl:apply-templates select="#*|node()" mode="document" />
</xsl:copy>
</xsl:template>
<xsl:template match="draft-comment" mode="document" />
Then you can use xsl:apply-templates instead of xsl:copy-of
<xsl:variable name="fileContent">
<xsl:apply-templates select="document($fileSrc)" mode="document" />
</xsl:variable>
Note that xsl:copy-of does a deep-copy, and your existing statement will copy the root element and everything under it just as long as it doesn't have a child node called draft-comment

How to display value in xslt variable

how can I store element with attributes into xslt variable and then display element through this variable ?
Example:
<element name="value1" attribute2="value2" />
I tried something like this:
<xsl:variable name="myVariable" select="../element[#name=value1]" />
and then display:
<xsl:template match="..">
<xsl:value-of select="$myVariable" />
</xsl:template>
And I want to display element with given name with all attributes.
Thanks
Krp0
You have been missing the qoutes around value1. To access the value of the variable use xsl:copy-of which copies an element with all attributes.
<xsl:template match="/">
<xsl:variable name="myVariable" select="element[#name='value1']" />
<xsl:copy-of select="$myVariable" />
</xsl:template>
value-of creates a text node with the string value of the selected value, if you want to copy a node to the output use copy-of, e.g. <xsl:copy-of select="$myVariable"/>.

XSLT - How to refer to a current node value using xsl:choose?

I try to create a variable, which I can use in a later template:
<xsl:variable name="fc">
<xsl:choose>
<xsl:when test="self::node()='element1'">gray</xsl:when>
<xsl:otherwise>red</xsl:otherwise>
</xsl:choose>
</xsl:variable>
Unfortunately it does not work.
<xsl:template match="element1">
<h1><font color="{$fc}"><xsl:value-of select="self::node()"/></font></h1>
</xsl:template>
What am I doing wrong?
Here is the extensive code:
XML:
<root
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.test.com scheme.xsd" xmlns="http://www.test.com" xmlns:tst="http://www.test.com">
<elementA>
<elementB tst:name="name">
<elementC tst:name="name">
<element1> Test1 </element1>
<element2> Test2 </element2>
</elementC >
</elementB>
</elementA>
</root>
All the elements are qualified and part of the namespace "http://www.test.com".
XSLT:
<xsl:template match="/">
<html>
<body><xsl:apply-templates select="tst:root/tst:elementA/tst:elementB/tst:elementC/tst:element1"/>
</body>
</html>
</xsl:template>
<xsl:variable name="var_fc">
<xsl:choose>
<xsl:when test="local-name(.)='tst:element1'">gray</xsl:when>
<xsl:otherwise>red</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:template match="tst:element1">
<h2><font color="{$var_fc}"><xsl:value-of select="self::node()"/></font></h2>
</xsl:template>
As a result, element1 should turn gray, but it always turn red.
You can't use a variable for this, as the content of an xsl:variable is evaluated just once at definition time, whereas you want to evaluate some logic every time the variable is referenced, in the current context at the point of reference.
Instead you need a template, either a named one:
<xsl:template name="fc">
<xsl:choose>
<xsl:when test="local-name()='element1'">gray</xsl:when>
<xsl:otherwise>red</xsl:otherwise>
</xsl:choose>
</xsl:template>
or (better) a pair of matching templates with a mode, to let the template matcher do the work:
<!-- match any node whose local name is "element1" -->
<xsl:template mode="fc" match="node()[local-name() = 'element1']">gray</xsl:template>
<!-- match any other node -->
<xsl:template mode="fc" match="node()">red</xsl:template>
When you want to use this logic:
<h1>
<font>
<xsl:attribute name="color">
<xsl:apply-templates select="." mode="fc" />
</xsl:attribute>
Seeing as you have the tst prefix mapped in your stylesheet you could check the name directly instead of using the local-name() predicate:
<xsl:template mode="fc" match="tst:element1">gray</xsl:template>
<xsl:template mode="fc" match="node()">red</xsl:template>
XSLT variables are designed not to be changeable. Actually they could be named constants. If your variable fc is created global, it will use the root element for choose. You have to use choose in the actual template to be tested against the current element. If you want to have "red" and "gray" defined only once, create two variables with just that text content and use these instead the plain text in the choose.
Maybe it is a typo:
<xsl:when test=self::node()='element1'">gray</xsl:when>
should be:
<xsl:when test="self::node()='element1'">gray</xsl:when>
there is a missing quote.
I think instead of test="self::node()='element1'" you want test="self::element1" or test="local-name(.) = 'element1'".
A couple of other errors in your code:
(1) self::node() = 'element1'
tests whether the content of the element is "element1", not whether its name is "element1"
(2) local-name(.)='tst:element1'
will never be true because the local name of a node never contains a colon.
Experienced users would often write this code using template rules:
<xsl:template mode="var_fc" match="tst:element1">gray</xsl:template>
<xsl:template mode="var_fc" match="*">red</xsl:template>
and then
<xsl:apply-templates select="." mode="var_fc"/>

XSL: replacing <br><br/> with another character

I have an input xml document that I am transforming which has this content in an node:
<misc-item>22 mm<br></br><fraction>7/8</fraction> in.</misc-item>
When I create a variable by selecting 'misc-item', the br and fraction tags disappear. However, if I create a variable using 'misc-item/br' and test to see if it is finding the br, the test seems to work.
What I want to do is make the
'<br></br>'
into a space or semicolon or something, but I have had no luck. I tried getting the siblings of 'misc-item/br', but it has none. I checked the child count of 'misc-item' and it is one.
Any help greatly appreciated.
I looked at the post identified as possible dupe. I tried this to no avail:
<xsl:template match="#*|node()" mode='PageOutput'>
<xsl:copy>
<xsl:apply-templates select="#*|node()" mode="PageOutput" />
</xsl:copy>
</xsl:template>
<xsl:template match="br" mode='PageOutput'>
<xsl:value-of select="' '" />
</xsl:template>
Since I am not ignoring an element as in the suggested dupe, but rather substituting, this doesn't seem to be quite right.
When I create a variable by selecting 'misc-item', the br and fraction tags disappear. However, if I create a variable using 'misc-item/br' and test to see if it is finding the br, the test seems to work.
When you create a variable you're storing a reference to the misc-item node in the variable. If you ask for the value-of that node you'll get just the text, with elements stripped out, but the variable still holds the node itself.
This is probably something you need to tackle using apply-templates instead of value-of. A common theme is to have an "identity template" which essentially copies everything as-is but can be overridden with different behaviour for certain nodes by providing more specific templates.
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#*|node()" /></xsl:copy>
</xsl:template>
<!-- replace any br element with a semicolon -->
<xsl:template match="br">;</xsl:template>
You can use a mode to restrict these templates for use in specific situations only
<xsl:template match="#*|node()" mode="strip-br">
<xsl:copy><xsl:apply-templates select="#*|node()" mode="strip-br" /></xsl:copy>
</xsl:template>
<!-- replace any br element with a semicolon -->
<xsl:template match="br" mode="strip-br">;</xsl:template>
and now you can use e.g.
<xsl:apply-templates select="$miscitem/node()" mode="strip-br" />
instead of <xsl:value-of select="$miscitem"/> to get the result you're after.