I am transforming documents from one XML standard to another. One of the requirements is that a numbered list uses alphabetical instead of roman numbering. I can create the unicode from the list position but it seems impossible to insert those into the XML output.
Maybe I am simply not seeing the obvious solution here. In JavaScript I would be using the fromCharCode( ) function but I have not yet found a similar option in XSLT.
I am using XSL 2.0 but could also use 3.0 if needed to make things easier.
I created a simple XML plus XSL to show the problem I need to solve. The actual files are much too big to be sharing here.
Sample XML input document:
<doc>
<p>Some text</p>
<p>Some more text</p>
</doc>
Required output:
<doc>
<list>
<list-item>
<label>A</label>
<p>Some text</p>
</list-item>
<list-item>
<label>B</label>
<p>Some more text</p>
</list-item>
</list>
</doc>
I have tried this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" encoding="UTF-8"/>
<xsl:template match="/doc">
<xsl:copy>
<list>
<xsl:apply-templates select="p"/>
</list>
</xsl:copy>
</xsl:template>
<xsl:template match="p">
<xsl:variable name="number" as="xs:integer" select="position()"/>
<list-item>
<label>
<xsl:value-of select="concat('&#',$number + 65,';')" disable-output-escaping="yes"/>
</label>
<xsl:copy-of select="."/>
</list-item>
</xsl:template>
</xsl:stylesheet>
I have used disable-output-escaping on other generated items before (e.g. to put angular brackets into the XML output), but it seems that the standard character codes are not being handled in the same way. My output from the above XSL shows up like this:
doc>
<list>
<list-item>
<label>B</label>
<p>Some text</p>
</list-item>
<list-item>
<label>C</label>
<p>Some more text</p>
</list-item>
</list>
</doc>
Is there any way to do this elegantly (i.e. without me having to create a huge xsl:choose to call out every possible integer label value and then explicitly creating the alphabetical labels?
You can use codepoints-to-string() and have it convert the number into the letter.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/doc">
<xsl:copy>
<list>
<xsl:apply-templates select="p"/>
</list>
</xsl:copy>
</xsl:template>
<xsl:template match="p">
<list-item>
<label>
<xsl:value-of select="codepoints-to-string(position() + 64)"/>
</label>
<xsl:copy-of select="."/>
</list-item>
</xsl:template>
</xsl:stylesheet>
Or you could use xsl:number with value="position()" and format="A"
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/doc">
<xsl:copy>
<list>
<xsl:apply-templates select="p"/>
</list>
</xsl:copy>
</xsl:template>
<xsl:template match="p">
<list-item>
<label>
<xsl:number format="A" value="position()"/>
</label>
<xsl:copy-of select="."/>
</list-item>
</xsl:template>
</xsl:stylesheet>
A quick solution for values up to 26 (='Z') would be
<xsl:template match="p">
<xsl:variable name="alphabet" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:variable name="number" as="xs:integer" select="position()"/>
<list-item>
<label><xsl:value-of select="substring($alphabet,$number,1)"/></label>
<xsl:copy-of select="."/>
</list-item>
</xsl:template>
The output is as desired.
This could be extended to 26*26 by using a div and an xsl:if.
Related
I want to remove space between two string and node in XSLT. I am using XSLT 2.0
Input :
<p type="c"><doc ref="core" id="k12234"><t/>AWS H <t/>(ever over)<t/></doc><refformat="no" ref="core" rid="ck1123"/>00</p>
Output should be :
<p type="c"><doc ref="core" id="k12234"><t/>AWS H<t/>(ever over)<t/></doc><refformat="no" ref="core" rid="ck1123"/>00</p>
the space between AWS H and <t/> should be removed from output.
If you want to remove the trailing space of any text node that is followed by a <t /> node, you could do this....
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="no"/>
<xsl:template match="text()[following-sibling::node()[1][self::t]]">
<xsl:value-of select="replace(., '\s+$', '')" />
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note, you could use normalize-space here, instead of replace, but this would remove leading spaces too, which may or may not be want you want.
Note, if you only wanted to target text nodes beginning with AWS you could adjust the template match like so:
<xsl:template match="text()[starts-with(., 'AWS')][following-sibling::node()[1][self::t]]">
See this in action at http://xsltfiddle.liberty-development.net/6r5Gh3W
Input
<?xml version="1.0" encoding="UTF-8"?>
<root>
<ajeet>aaaaa </ajeet>
<kumar> bbbbb</kumar>
</root>
xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<singh><xsl:value-of select="normalize-space(//ajeet)"/></singh>
</xsl:template>
</xsl:stylesheet>
output:-
<?xml version="1.0" encoding="UTF-8"?>
<singh>aaaaa</singh>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
Try this using normalize-space
See below code, space removal happen only between "text() node and <t>".:
Input XML:
<root>
<p type="c"><doc ref="core" id="k12234">The <ii>pp</ii> the <t/>AWS H <t/>(ever over) <l>the </l><t/></doc><ref format="no" ref="core" rid="ck1123"/>00</p>
<p type="c"><doc ref="core" id="k12234"><t/>AWS H <t/>(ever over)<t/></doc><ref format="no" ref="core" rid="ck1123"/>00</p>
</root>
XSLT:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
</xsl:template>
<xsl:template match="doc">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:for-each-group select="node()"
group-adjacent="exists(following-sibling::node()[1][self::t]) and self::text()">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:value-of select="normalize-space()"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Result:
<root>
<p type="c"><doc ref="core" id="k12234">The <ii>pp</ii>the<t/>AWS H<t/>(ever over) <l>the </l><t/></doc><ref format="no" ref="core" rid="ck1123"/>00</p>
<p type="c"><doc ref="core" id="k12234"><t/>AWS H<t/>(ever over)<t/></doc><ref format="no" ref="core" rid="ck1123"/>00</p>
</root>
May be my XSL approach is wrong? please correct me the way to handle this situation
I want to grab XPATHs and Attrs from a mapping file, then use XPATH to match, and apply attributes to XML.
Here is my 3 inputs files:
mappings.xml
<?xml version="1.0" encoding="UTF-8"?>
<mappings>
<map xpath="//title" class="title" others="moreToCome" />
<map xpath="//subtitle" class="subtitle" others="moreToCome" />
<map xpath="//p" class="p" others="moreToCome" />
</mappings>
Source.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title>title text</title>
<subtitle>subtitle text</subtitle>
<p>subtitle text</p>
</root>
StyleMapping.xsl
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="fMappings" select="document('mappings.xml')" />
<xsl:variable name="xpath"><xsl:text>justToMakeItGlobal</xsl:text></xsl:variable>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
<!-- loop thru map in mappings.xml -->
<xsl:for-each select="$fMappings//mappings/map">
<xsl:call-template name="dyn">
<xsl:with-param name="xpath" select="#xpath" />
<xsl:with-param name="class" select="#class" />
<xsl:with-param name="others" select="#others" />
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template match="$xpath" mode="dyn">
<xsl:param name="xpath"/>
<xsl:param name="class"/>
<xsl:param name="others"/>
<xsl:attribute name="class"><xsl:value-of select="$class" /></xsl:attribute>
<xsl:attribute name="others"><xsl:value-of select="$others" /></xsl:attribute>
</xsl:template>
</xsl:stylesheet>
This is what is planning to do, but i'm not getting the correct way of doing it in XSLT:
1. Read mappings.xml file
2. Loop thru each map tag
3. grab xpath and attr's
4. apply template match/select with above xpath
5. add attr's to above selected nodes
output.xml
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title class="title" others="moreToCome">title text</title>
<subtitle class="subtitle" others="moreToCome">subtitle text</subtitle>
<p class="p" others="moreToCome">subtitle text</p>
</root>
I don't think you can have a template with a calculated match pattern. Let me suggest a different approach:
mappings.xml
<?xml version="1.0" encoding="UTF-8"?>
<mappings>
<map elem="title" class="Title" others="moreToCome1" />
<map elem="subtitle" class="Subtitle" others="moreToCome2" />
<map elem="p" class="P" others="moreToCome3" />
</mappings>
stylesheet
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:variable name="mappings" select="document('mappings.xml')/mappings" />
<xsl:template match="*">
<xsl:variable name="elem" select="name()" />
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:if test="$elem = $mappings/map/#elem">
<xsl:attribute name="class">
<xsl:value-of select="$mappings/map[#elem=$elem]/#class"/>
</xsl:attribute>
<xsl:attribute name="others">
<xsl:value-of select="$mappings/map[#elem=$elem]/#others"/>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Testing with the following source XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<title original="yes">title text</title>
<subtitle>subtitle text</subtitle>
<p>para text</p>
<nomatch attr="test">another text</nomatch>
</root>
results in:
<?xml version="1.0" encoding="utf-8"?>
<root>
<title original="yes" class="Title" others="moreToCome1">title text</title>
<subtitle class="Subtitle" others="moreToCome2">subtitle text</subtitle>
<p class="P" others="moreToCome3">para text</p>
<nomatch attr="test">another text</nomatch>
</root>
I am working XSLT where the source looks like this.
Source:
<Data>
<AB>all</AB>
<AB>all2</AB>
<CD>hhhhhh</CD>
<DE>hhhshhh</DE>
</Data>
Need to write XSLT to get output as
<Info>
<XXX>
<TTT value="all"/>
<TTT value="all2"/>
</XXX>
<!-- ....-->
<!-- ..to het all the elements.. -->
</Info>
I have to write xslt to match tag.
<xsl:template match="AB">
</xsl:template>
I can do it by matching Data tag.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="Data">
<info>
<XXX>
<xsl:for-each select="AB">
<TTT>
<xsl:attribute name="value">
<xsl:value-of select="."/>
</xsl:attribute>
</TTT>
</xsl:for-each>
</XXX>
</info>
</xsl:template>
</xsl:stylesheet>
Can any one help me out how to do it by matching AB tag
<xsl:template match="AB">
</xsl:template>
Thank you.
I think you are asking how do you use xsl:apply-templates. If so, your XSLT would look like this
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="Data">
<info>
<XXX>
<xsl:apply-templates select="AB"/>
</XXX>
</info>
</xsl:template>
<xsl:template match="AB">
<TTT value="{.}"/>
</xsl:template>
</xsl:stylesheet>
Do also note the use of Attribute Value Templates in the AB template to simplify the XSLT.
If you also require the other non-AB elements to be output unchanged, you would make use of the identity transform in your XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="Data">
<info>
<XXX>
<xsl:apply-templates select="AB"/>
</XXX>
<xsl:apply-templates select="node()[not(self::AB)]" />
</info>
</xsl:template>
<xsl:template match="AB">
<TTT value="{.}"/>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
This would also match all non-AB elements, outputing following the XXX element. In your case, it would output the following:
<info>
<XXX>
<TTT value="all" />
<TTT value="all2" />
</XXX>
<CD>hhhhhh</CD>
<DE>hhhshhh</DE>
</info>
Of course, there is no reason you couldn't have other templates matching elements like CD or DE to transform those too.
I have written a package for converting XMLs to ePubs. Everything works fine, except some cases, where blank namespace (xmlns="") nodes are being written to the result-documents. Prior to transformation, I prepared temporary variables for holding main-segments(i.e., meta, body etc.) and finally copied the nodes(using xsl:copy-of[#copy-namespaces='no'] instruction) to result-document. I also have used #exclude-result-prefixes='ns_list_sep_by_space' within xsl:transform element and still not able to get desired result.
oXygen IDE shows a message in pop-up saying:
When using xsl:copy-of the new elements will also have namespace nodes copied from the original element node, unless they are excluded by specifying copy-namespaces="no". If this attribute is omitted, or takes the value yes, then all the namespace nodes of the original element are copied to the new element. If it takes the value no, then none of the namespace nodes are copied: however, namespace nodes will still be created in the result tree as required by the namespace fixup process.
Here is some more details of my problem:
Main stylesheet:
main.xsl:main caller
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
xmlns:cylian="local-ns-for-extension-functions"
exclude-result-prefixes="xs xd cylian"
version="2.0">
<xsl:import href="modules/core.xsl"/>
<xsl:variable name="base" select="base-uri()" as="xs:anyURI"/>
<xsl:template match="/">
<xsl:call-template name="procA"/>
</xsl:template>
</xsl:transform>
Main stylesheet:
core.xsl: core processing unit
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
xmlns:cylian="local-ns-for-extension-functions"
exclude-result-prefixes="xs xd cylian"
version="2.0">
<xsl:import href="sub1.xsl"/>
<xsl:import href="sub2.xsl"/>
<!--and more-->
<!-- variable to hold intermediate results for stage1 -->
<xsl:variable name="stage1">
<cylianz>
<xsl:copy-of select="$a" copy-namespaces="no"/>
<xsl:copy-of select="$b" copy-namespaces="no"/>
<!--and more-->
</cylianz>
</xsl:variable>
<!-- variable to hold intermediate results for stage2 -->
<xsl:variable name="stage2">
<cylianz>
<xsl:for-each select="$stage1//cylian">
<xsl:sort select="#pos"/>
<xsl:sequence select="."/>
</xsl:for-each>
</cylianz>
</xsl:variable>
<xsl:template name="procA">
<xsl:for-each select="$stage2//cylian">
<xsl:result-document href="{concat($outdir,#href)}" format="general">
<xsl:call-template name="procB">
<xsl:with-param name="context" select="."/>
<xsl:with-param name="title">
<xsl:value-of select="$book_title"/>
</xsl:with-param>
</xsl:call-template>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
<xsl:template name="procB">
<xsl:param name="context"/>
<xsl:param name="title"/>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<xsl:call-template name="header">
<xsl:with-param name="title" select="$title"/>
</xsl:call-template>
</head>
<body>
<div id="root">
<xsl:apply-templates select="."/>
</div>
</body>
</html>
</xsl:template>
<!--
1/ other rules are shortened for clarity
2/ declaration «xmlns:cylian='local-ns-for-extension-functions'» has to retain, some parts of transformation uses some extension functions from that namespace
-->
</xsl:transform>
and here's the output:
a.html
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta xmlns="" http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title xmlns="">BookTitle</title>
<!--
2012.04.16 - 18:27:36 [XSLT processor: SAXON 9.1.0.5 from Saxonica]
-->
<link xmlns="" href="isbn.css" type="text/css" rel="stylesheet"/>
</head>
<body>
<div id="root">
<div xmlns="" id="a1">
<!--...-->
</div>
</div>
</body>
</html>
I hope it would be easier to understand what's the problem is going on. All suggestions are welcome. Thanks in advance.
Well we need to see your code to be sure but I suspect you have e.g.
<xsl:template match="/">
<foo xmlns="http://example.com/ns">
<xsl:apply-templates/>
</foo>
</xsl:template>
<xsl:template match="whatever">
<bar/>
</xsl:template>
and then you get
<foo xmlns="http://example.com/ns">
<bar xmlns=""/>
</foo>
while you want
<foo xmlns="http://example.com/ns">
<bar/>
</foo>
To fix that make sure you move the default namespace declaration on the xsl:stylesheet element with e.g.
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://example.com/ns">
version="1.0">
<xsl:template match="/">
<foo>
<xsl:apply-templates/>
</foo>
</xsl:template>
<xsl:template match="whatever">
<bar/>
</xsl:template>
</xsl:stylesheet>
that way it applies to all result elements created in different templates.
[edit]
Based on the samples you have provided now I think my suggestion is right, only with several files you need to make sure that all stylesheet modules you have put xmlns="http://www.w3.org/1999/xhtml" on the xsl:stylesheet respectively xsl:transform elements so that all result elements end up in the XHTML namespace.
[second edit]
I think you want
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
xmlns:cylian="local-ns-for-extension-functions"
exclude-result-prefixes="xs xd cylian"
version="2.0">
<xsl:import href="sub1.xsl"/>
<xsl:import href="sub2.xsl"/>
<!--and more-->
<!-- variable to hold intermediate results for stage1 -->
<xsl:variable name="stage1" xmlns="">
<cylianz>
<xsl:copy-of select="$a" copy-namespaces="no"/>
<xsl:copy-of select="$b" copy-namespaces="no"/>
<!--and more-->
</cylianz>
</xsl:variable>
<!-- variable to hold intermediate results for stage2 -->
<xsl:variable name="stage2" xmlns="">
<cylianz>
<xsl:for-each select="$stage1//cylian">
<xsl:sort select="#pos"/>
<xsl:sequence select="."/>
</xsl:for-each>
</cylianz>
</xsl:variable>
<xsl:template name="procA">
<xsl:for-each select="$stage2//cylian">
<xsl:result-document href="{concat($outdir,#href)}" format="general">
<xsl:call-template name="procB">
<xsl:with-param name="context" select="."/>
<xsl:with-param name="title">
<xsl:value-of select="$book_title"/>
</xsl:with-param>
</xsl:call-template>
</xsl:result-document>
</xsl:for-each>
</xsl:template>
<xsl:template name="procB">
<xsl:param name="context"/>
<xsl:param name="title"/>
<html >
<head>
<xsl:call-template name="header">
<xsl:with-param name="title" select="$title"/>
</xsl:call-template>
</head>
<body>
<div id="root">
<xsl:apply-templates select="."/>
</div>
</body>
</html>
</xsl:template>
</xsl:transform>
And then if you have any additional modules supposed to produce XHTML elements make sure you put xmlns="http://www.w3.org/1999/xhtml" on the root element of the module or if you need to create elements in other namespaces as well then on any template supposed to output XHTML.
There are two kinds of "unwanted" namespace declarations that might appear in your output: declarations that are unwanted because they are redundant noise (they declare namespace prefixes that aren't used), and declarations that are unwanted because they put the elements in a different namespace from the one intended.
In the first case, XSLT provides features such as exclude-result-prefixes and copy-namespaces='no' to get rid of the noise.
In the second case (which is where I think you are), the namespace declarations are a symptom of the fact that the stylesheet author created the elements in the wrong namespace in the first place, and the solution is to look at the code that created the elements, and fix it. For example you might have written a literal result element <foo> that creates an element in no namespace, when you intended <foo xmlns="something"/> to create it in some other namespace.
Let's have this XML document:
<x:t xmlns:x="some:x">
<a/>
<b/>
</x:t>
Here is code that is probably similar to yours:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<t xmlns="some:x">
<xsl:copy-of select="*" copy-namespaces="no"/>
</t>
</xsl:template>
</xsl:stylesheet>
and it produces this unwanted result:
<t xmlns="some:x">
<a xmlns=""/>
<b xmlns=""/>
</t>
Why is this result produced?
Because you are using <xsl:copy-of> the nodes are copied "as-is", so elements don't change the namespace they are in. The attribute copy-namespaces="no" only specifies that the namespace nodes belonging to this element will be skipped from copying -- not that the element will change its own namespace.
Solution:
When we want to change the namespace an element is in (in this case from "no namespace" to "some:x", we shouldn't copy this element node.
Instead we must create a new element from this one, and specify the new namespace in which the new element should be:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<t xmlns="some:x">
<xsl:apply-templates select="*"/>
</t>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}" namespace="some:x">
<xsl:apply-templates select="node() | #*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the same XML document (above), the wanted, correct result is produced:
<t xmlns="some:x">
<a/>
<b/>
</t>
I have below scenario for my XML.
<content>
<para>text-1 <emphasis type="bold">text-2</emphasis> text-3</para>
</content>
I want to parse it like below
<content>
<p>text-1 <b>text-2</b> text-3</p>
</content>
I have created my XSLT as below
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" encoding="ISO-8859-1" indent="no"/>
<xsl:template name="para">
<p>
<xsl:value-of select="text()" disable-output-escaping="yes"/>
<xsl:for-each select="child::*">
<xsl:if test="name()='emphasis'">
<xsl:call-template name="emphasis"/>
</xsl:if>
</xsl:for-each>
</p>
</xsl:template>
<xsl:template name="emphasis">
<xsl:if test="attribute::type = 'bold'">
<b>
<xsl:value-of select="text()" disable-output-escaping="yes"/>
</b>
</xsl:if>
</xsl:template>
<xsl:template match="/">
<content>
<xsl:for-each select="content/child::*">
<xsl:if test="name()='para'">
<xsl:call-template name="para"/>
</xsl:if>
</xsl:for-each>
</content>
</xsl:template>
</xsl:stylesheet>
XSLT provided above is generating output like below
<content>
<p>text-1 text-3<b>text-2 </b></p>
</content>
Please guide me with your suggestions, how can I get my desire output?
To do this, you just need to extend the standard Identity Transform with special cases for matching your para and emphasis elements. For example, for para elements you would the following to replace para with p and then continue matching all the child nodes
<xsl:template match="para">
<p>
<xsl:apply-templates select="#*|node()"/>
</p>
</xsl:template>
So, given the following XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" />
<!-- This is the Identity Transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Replace para with p -->
<xsl:template match="para">
<p>
<xsl:apply-templates select="#*|node()"/>
</p>
</xsl:template>
<!-- Replace emphasis with b -->
<xsl:template match="emphasis[#type='bold']">
<b>
<xsl:apply-templates select="node()"/>
</b>
</xsl:template>
</xsl:stylesheet>
When applied to the following input XML
<content>
<para>text-1 <emphasis type="bold">text-2</emphasis> text-3</para>
</content>
The following is output
<content>
<p>text-1 <b>text-2</b> text-3</p>
</content>
You should be able to see how easy it is to extend to other cases should you input XML have more tags to transform.
do it like this ;)
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:template match="content">
<content><xsl:apply-templates select="para" /></content>
</xsl:template>
<xsl:template match="emphasis [#type='bold']">
<b><xsl:value-of select="." /></b>
</xsl:template>
</xsl:stylesheet>
when you do it like this the default template will catch text-1 and text-3