I have two templates. I want to combine them together.
<xsl:template match="abc//para/c">
<p type="ccc">
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="abc/c">
<p type="ccc">
<xsl:apply-templates/>
</p>
</xsl:template>
Tried code:
<xsl:template match="abc//para/c or abc/c">
<p type="ccc">
<xsl:apply-templates/>
</p>
</xsl:template>
My tried code is not success.
Use match="abc//para/c | abc/c".
Related
I want to add multiple matches in except operator.
Example:
<root>
<div>
<span style="font-family:'Work Sans', sans-serif;">
</span>
<h3>hi</h3>
<ol><li>hello</li></ol>
<ul><li>hello</li></ul>
<p>name</p>
</div>
</root>
Expected result: Want to convert div tag to p tag and then move only h3,ol,ul,p tag out of it if present.
<root>
<p>
<span style="font-family:'Work Sans', sans-serif;">
</span>
</p>
<h3>hi</h3>
<ol><li>hello</li></ol>
<ul><li>hello</li></ul>
<p>name</p>
</root>
I tried this:
<xsl:template match="div">
<p>
<xsl:copy-of select="* except h3"/>
</p>
<xsl:copy-of select="h3"/>
</xsl:template>
Above xslt results to :
<root>
<p>
<span style="font-family:'Work Sans', sans-serif;">
</span>
<ol><li>hello</li></ol>
<ul><li>hello</li></ul>
<p>name</p>
</p>
<h3>hi</h3>
</root>
Is there any way to add mutiple element names in except operator like <xsl:copy-of select="* except h3 and ol"/>
Another approach i tried:
<xsl:template match="div[p | ol | ul | h3 | h2]">
<xsl:apply-templates/>
</xsl:template>
<!-- convert <div> to <p> if it's direct child is not one of p,ol,ul -->
<xsl:template match="div[not(p | ol | ul | h3 | h2)]">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
And this results to which is wrong as i still want span tag to be under p tag:
<root><span style="font-family:'Work Sans', sans-serif;">
</span>
<h3>hi</h3>
<ol><li>hello</li></ol>
<ul><li>hello</li></ul>
<p>name</p></root>
In stead of using xsl:copy you could just use the xsl:apply-templates approach like this:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="node()|#*" name="copy">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="div">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="div/span">
<p>
<xsl:call-template name="copy"/>
</p>
</xsl:template>
</xsl:stylesheet>
The except operator was introduced in XPath 2.0 so it doesn't make any sense on how to use it with XSLT 1.0 which uses XPath 1.0.
As for its use where supported, you can of course do e.g. * except (h3, ol).
In XPath 1.0 you can try e.g. *[not(self::h3|self::ol)].
I have an XSL 1.0 document with the following:
<div class="workgroup_title">
<xsl:value-of select="./#name"/>
</div>
I need to set the color for this element. The color is in the XML file
<abc.xyz.color>FF5733</abc.xyz.color>
To get it, I use this:
<xsl:value-of select="./abc.xyz.color"/>
What I would have liked to do is
<div class="workgroup_title" style="color:"#<xsl:value-of select="./abc.xyz.color"/>>
<xsl:value-of select="./#name"/>
</div>
That's not allowed, though.
Or:
<xsl:attribute style="color:">#<xsl:value-of select="./abc.xyz.color"/></xsl:attribute>
But color is not one of the attributes that can be set like that.
You can use attribute value templates to compute (parts of) the value of a literal result element: <div style="color: #{abc.xyz.color}">...</div>
The following templates should suffice your needs:
<xsl:template match="text()" /> <!-- Removes the text from the <abc.xyz.color>FF5733</abc.xyz.color> element -->
<xsl:template match="/*"> <!-- Copies the root element and its namespace -->
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template match="div[#class='workgroup_title']"> <!-- Applies the template to the <div> element -->
<xsl:copy>
<xsl:attribute name="style"><xsl:value-of select="concat('color: #',../abc.xyz.color,';')"/></xsl:attribute>
<xsl:copy-of select="node()|#*" />
</xsl:copy>
</xsl:template>
Its output is:
<root xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<div style="color: #FF5733;" class="workgroup_title">
<xsl:value-of select="./#name"/>
</div>
</root>
I am fairly new to XSLT and this my xml
<q>
<w>
<p>
<b>b1</b>
</p>
<p>p1</p>
<p>p2</p>
<p>p3</p>
<p>
<b>b2</b>
</p>
<p>
<b>b3</b>
</p>
<p>p4</p>
<p>p5</p>
<p>
<b>b4</b>
</p>
<p>p6</p>
</w>
</q>
I need my output to look something like this
<position_1_b1>
<p>p1</p>
<p>p2</p>
<p>p3</p>
</position_1_b1>
<position_2_b3>
<p>p4</p>
<p>p5</p>
</position_2_b3>
<position_3_b4>
<p>p6</p>
</position_3_b4>
There is no b2 related tag in output because next 'P' element has an element 'B' in it!
<p><b>b2</b></p>
<p><b>b3</b></p>
Thanks in advance!!
You can use grouping in XSLT2.0
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output indent="yes"></xsl:output>
<xsl:template match="w">
<xsl:for-each-group select="*" group-starting-with="p[b][following-sibling::*[1][self::p][not(b)]]">
<xsl:element name="{concat('position_', position(), '_', normalize-space(.))}">
<xsl:apply-templates select="current-group() except self::p[b]"/>
</xsl:element>
</xsl:for-each-group>
</xsl:template>
<xsl:template match="p[not(b)]">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="p[b]"/>
I have the following XML
<title>
This is a <highlight>test</highlight> thanks.
</title>
and want to convert into
<span class="title">this is a <span class="highlight">test</span> thanks.</span>
I try this xslt, only can ge the text inside title tag, how can I also convert the highlight tag?
<span class="title"><xsl:value-of select="title"/></span>
<xsl:template match="title">
<span class="title">
<xsl:apply-templates />
</span>
</xsl:template>
<xsl:template match="highlight">
<span class="highlight">
<xsl:apply-templates />
</span>
</xsl:template>
or, if you want, collapse it into a single template:
<xsl:template match="title|highlight">
<span class="{name()}">
<xsl:apply-templates />
</span>
</xsl:template>
Key point is the <xsl:apply-templates /> - it runs all child nodes of the current node through the appropriate templates. In the upper variant, the appropriate templates are separate, in the lower variant the one template is called recursively.
There is a default rule defined in XSLT that copies text nodes. All text is run through this rule by <apply-templates>, so text nodes appear in the output autmatically.
Use xsl:copy-of instead of xsl:value-of if you want a full copy of the node and all of its children:
<span class="title"><xsl:copy-of select="title"/></span>
But for what you are trying to do, I would create one template for the title element and one for the highlight element:
<xsl:template match="title">
<span class="title"><xsl:value-of select="." /></span>
<xsl:apply-templates />
</xsl:template>
<xsl:template match="highlight">
<span class="highlight"><xsl:value-of select="." /></span>
</xsl:template>
I have a item list and for each item I want to make it an url.
List:
<root>
<tags>
<tag>open source</tag>
<tag>open</tag>
<tag>advertisement</tag>
<tag>ad</tag>
</tags>
</root>
XSLT:
<xsl:template match="*">
<div class="tags">
<xsl:for-each select="/post/tags/tag">
<a href="#">
<xsl:value-of select="//tag"/>
</a>
</xsl:for-each>
</div>
</xsl:template>
Output:
<div class="tags">
open source
open source
open source
open source
</div>
What am I doing wrong?
A more XSLT way of doing the correct thing is add a "tag" template and modify your original:
<xsl:template match="*">
<div class="tags">
<xsl:apply-templates select="tag" />
</div>
</xsl:template>
<xsl:template match="tag">
<a href="#">
<xsl:value-of select="."/>
</a>
</xsl:template>
What you are doing with the value-of expression is selecting all of the tag nodes in the xml document:
<xsl:value-of select="//tag"/>
The effect of that is that only the first selected node will be used for the value.
You can use the following instead:
<xsl:value-of select="."/>
Where select="." will select the current node from the for-each.