Replace the set of characters with special characters in xslt - xslt

Source:
<txt>
<Data>
<div class="label">
<span>Welcome</span>
<span id="UserName"></span>.
</div>
</Data>
</txt>
Output required:
<Data>
<div class="label">
<span>Welcome</span>
<span id="UserName"></span>.
</div>
</Data>
Rule:
I want to replace
< with <
> with >
There are other characters also, for simplicity I have mentioned two only.
I am not sure how to search for a string in xslt and replace it.

You could achieve this by using disable-output-escaping
<xsl:template match="txt">
<xsl:value-of select="." disable-output-escaping="yes" />
</xsl:template>
That should give you the output you require.

Related

XSL flatten with inherit

I want to flatten an XML document such that every element would copy the attributes of its parent and convert <span/> into <text/>
Input:
<el value="
<span bold="true">
one
<span italics="true">
two
<span superscript="true">
three
</span>
</span>
</span>
<span subscript="true">
four
</span>
"/>
Output:
<text bold="true">one</text>
<text bold="true" italics="true">two</text>
<text bold="true" italics="true" superscript="true">three</text>
<text subscript="true">four</text>
I've tried using copy-of with .. but that obviously only copies one level up from the input. I presume I need a variable but I am unsure of how to operate on it - it doesn't seem like I can do <xsl:value-of select="$text-element"><!--call template--></xsl:value-of>. The fact that this is a string inside an attribute doesn't help either...
Something like this might help, once you make the XML well-formed:
<xsl:template match="text()">
<text>
<xsl:copy-of select="ancestor::*/#*"/>
<xsl:value-of select="normalize-space()"/>
</text>
</xsl:template>

xslt: XPath select elements with specific attribute value

Input:
<list list-type="simple" specific-use="front">
<list-item><p>Preface <xref rid="b-9781783084944-FM-001" ref-type="sec">00</xref></p></list-item>
<list-item><p>Series Title <xref rid="b-9781783084944-FM-003" ref-type="sec">00</xref></p></list-item>
<list-item><p>Dedication</p></list-item>
<list-item><p>Acknowledgments <xref rid="b-9781783084944-FM-005" ref-type="sec">00</xref></p></list-item>
<list-item><p>Contributors <xref rid="b-9781783084944-FM-006" ref-type="sec">00</xref></p></list-item>
<list-item><p>Glossary <xref rid="b-9781783084944-FM-008" ref-type="sec">00</xref></p></list-item>
</list>
I need output lik below
<div class="pagebreak" id="b-9781783084944-FM-002">
<h2 class="PET">CONTENTS</h2>
<div class="TocPrelims">Preface</div>
<div class="TocPrelims">Series Title </div>
</div>
My xslt:
<xsl:template match="list[#specific-use='front'][#list-type='simple']/list-item/p">
<div class="TocPrelims">
<a>
<xsl:attribute name="href">
<xsl:text>#toc</xsl:text>
<xsl:copy-of select="//list[#specific-use='front'][#list-type='simple']/list-item/p/xref[#rid]"/>
</xsl:attribute>
<xsl:apply-templates/>
</a>
</div>
</xsl:template>
Above coding of mine is not correct.. pls give suggestions.
You have a problem with this line:
<xsl:copy-of select="//list[#specific-use='front'][#list-type='simple']/list-item/p/xref[#rid]"/>
Firstly, the condition will select all xref elements, but you only need the one for the current p you are positioned on. Secondly, it is selecting the xref element if it has an rid attribute, but you actually want to select the rid attribute. You also really want to use xsl:value-of here
<xsl:value-of select="xref/#rid"/>
Try this template instead:
<xsl:template match="list[#specific-use='front'][#list-type='simple']/list-item/p">
<div class="TocPrelims">
<a>
<xsl:attribute name="href">
<xsl:text>#toc</xsl:text>
<xsl:value-of select="xref/#rid"/>
</xsl:attribute>
<xsl:value-of select="text()[1]" />
</a>
</div>
</xsl:template>
In fact, you can make use of Attribute Value Templates to simplify it to this:
<xsl:template match="list[#specific-use='front'][#list-type='simple']/list-item/p">
<div class="TocPrelims">
<a href="#toc{xref/#rid}">
<xsl:value-of select="text()[1]" />
</a>
</div>
</xsl:template>

XSLT transform of XML document to XHTML document

Here's my template:
<xsl:template name="rec">
<xsl:for-each select="*">
<div class="{local-name()}">
<xsl:for-each select="#*">
<xsl:attribute name="data-{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
<xsl:value-of select="text()" />
<xsl:call-template name="rec" />
</div>
</xsl:for-each>
</xsl:template>
Given a document like so:
<test>
<item value="1">Item 1 Text</item>
<item value="2">Item 2 Text</item>
</test>
The above transform will turn it into:
<div class="test">
<div class="item" data-value="1">Item 1 Text</div>
<div class="item" data-value="2">Item 2 Text</div>
</div>
The problem I'm having, is that this transform doesn't respect text nodes properly, and I don't have enough background with XSLT to figure out how to fix it. Here's the problem: given xml like so:
<para>This is a <emphasis>paragraph</emphasis> people!</para>
I would like to see the following output:
<div class="para">This is a <div class="emphasis">paragraph</div> people!</div>
The problem is that I'm not getting this - I'm getting this:
<div class="para">This is a <div class="emphasis">paragraph</div></div>
Notice the missing 'people!' text node. How can I fix my XSLT above to provide me with the output I need?
One problem is that
<xsl:value-of select="text()" />
just selects the value of the first child text node, and outputs it.
The easiest way to do this right is probably to use <xsl:apply-templates> instead of <xsl:call-template>.
Then instead of
<xsl:for-each select="*">
and
<xsl:value-of select="text()" />
you can use
<xsl:apply-templates />
which will apply the appropriate template to each child element and text node, in order, not skipping any.
Here is a complete implementation:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="*">
<div class="{local-name()}">
<xsl:for-each select="#*">
<xsl:attribute name="data-{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates />
</div>
</xsl:template>
</xsl:stylesheet>
Note the <xsl:apply-templates/>, which operates on all children of the context node, including text nodes, by default in absence of an explicit select attribute.
A default template is used for text nodes. This template simply copies them to the output.
Sample input:
<test>
<item value="1">Item 1 Text</item>
<item value="2">Item 2 Text</item>
<para>This is a <emphasis>paragraph</emphasis> people!</para>
</test>
produces the desired output:
<div class="test">
<div class="item" data-value="1">Item 1 Text</div>
<div class="item" data-value="2">Item 2 Text</div>
<div class="para">This is a <div class="emphasis">paragraph</div> people!</div>
</div>

how XSLT convert tag inside tag?

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>

XSLT: Foreach iterates for each item, but displays the value of the first item?

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.