Remove whitespace from HTML generated using XSL - xslt

Background
Maintain readable XSL source code while generating HTML without excessive breaks that introduce spaces between sentences and their terminating punctuation. From Rethinking XSLT:
White space in XSLT stylesheets is especially problematic because it serves two purposes: (1) for formatting the XSLT stylesheet itself; and (2) for specifying where whitespace should go in the output of XSLT-processed XML data.
Problem
An XSL template contains the following code:
<xsl:if test="#min-time < #max-time">
for
<xsl:value-of select="#min-time" />
to
<xsl:value-of select="#max-time" />
minutes
</xsl:if>
<xsl:if test="#setting">
on <xsl:value-of select="#setting" /> heat
</xsl:if>
.
This, for example, generates the following output (with whitespace exactly as shown):
for
2
to
3
minutes
.
All major browsers produce:
for 2 to 3 minutes .
Nearly flawless, except for the space between the word minutes and the punctuation. The desired output is:
for 2 to 3 minutes.
It might be possible to eliminate the space by removing the indentation and newlines within the XSL template, but that means having ugly XSL source code.
Workaround
Initially the desired output was wrapped in a variable and then written out as follows:
<xsl:value-of select="normalize-space($step)" />.
This worked until I tried to wrap <span> elements into the variable. The <span> elements never appeared within the generated HTML code. Nor is the following code correct:
<xsl:copy-of select="normalize-space($step)" />.
Technical Details
The stylesheet already uses:
<xsl:strip-space elements="*" />
<xsl:output indent="no" ... />
Related
Storing html tags within an xsl variable
Question
How do you tell the XSLT processor to eliminate that space?
Thank you!

Instead of using copy-of you can apply the identity template with an additional template that trims the spaces from the text nodes. You only create one variable like in your first workaround.
You call:
<li><xsl:apply-templates select="$step" mode="nospace" />.</li>
The templates:
<xsl:template match="text()" mode="nospace" priority="1" >
<xsl:value-of select="normalize-space(.)" />
</xsl:template>
<xsl:template match="node() | #*" mode="nospace">
<xsl:copy>
<xsl:apply-templates select="node() | #*" mode="nospace" />
</xsl:copy>
</xsl:template>

I. This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="t[#max-time > #min-time]">
<span>
<xsl:value-of select=
"concat('for ', #min-time, ' to ', #max-time, ' minutes')"/>
</span>
<xsl:apply-templates select="#setting"/>
<xsl:text>.</xsl:text>
</xsl:template>
<xsl:template match="#setting">
<span>
<xsl:value-of select="concat(' on ', ., ' heat')"/>
</span>
</xsl:template>
</xsl:stylesheet>
when applied on the following XML document (none has been presented!):
<t min-time="2" max-time="3" setting="moderate"/>
produces the wanted, correct result:
<span>for 2 to 3 minutes</span>
<span> on moderate heat</span>.
and it is displayed by the browser as:
for 2 to 3 minutes
on moderate heat.
When the same transformation is applied on this XML document:
<t min-time="2" max-time="3"/>
again the correct, wanted result is produced:
<span>for 2 to 3 minutes</span>.
and it is displayed by the browser as:
for 2 to 3 minutes.
II. Layout (visual) solution:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my" xmlns:gen="gen:gen" xmlns:gen-attr="gen:gen-attr"
exclude-result-prefixes="my gen">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<my:layout>
<span>for <gen-attr:min-time/> to <gen-attr:max-time/> minutes</span>
<gen-attr:setting><span> on <gen:current/> heat</span></gen-attr:setting>
<gen:literal>.</gen:literal>
</my:layout>
<xsl:variable name="vLayout" select="document('')/*/my:layout/*"/>
<xsl:variable name="vDoc" select="/"/>
<xsl:template match="node()|#*">
<xsl:param name="pCurrent"/>
<xsl:copy>
<xsl:apply-templates select="node()|#*">
<xsl:with-param name="pCurrent" select="$pCurrent"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="$vLayout">
<xsl:with-param name="pCurrent" select="$vDoc/*"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="gen-attr:*">
<xsl:param name="pCurrent"/>
<xsl:value-of select="$pCurrent/#*[name() = local-name(current())]"/>
</xsl:template>
<xsl:template match="gen-attr:setting">
<xsl:param name="pCurrent"/>
<xsl:variable name="vnextCurrent" select=
"$pCurrent/#*[name() = local-name(current())]"/>
<xsl:apply-templates select="node()[$vnextCurrent]">
<xsl:with-param name="pCurrent" select="$vnextCurrent"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="gen:current">
<xsl:param name="pCurrent"/>
<xsl:value-of select="$pCurrent"/>
</xsl:template>
<xsl:template match="gen:literal">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
This transformation gives us an idea how to make a visual (skeletal) representation of the wanted output and use it to "populate" it with the wanted data from the source XML document.
The result is identical with that of the first solution. If this transformation is run "as-is" it will produce a lot of namespaces -- they are harmless and will not be produced if the layout is in a separate XML file.

Related

XSLT 2.0 3.0 for-each context error when tokenizing attributes

Given this XML
<dmodule>
<content>
<warningsAndCautionsRef>
<warningRef id="w001" warningIdentNumber="warning-001">
</warningRef>
<warningRef id="w002" warningIdentNumber="warning-002">
</warningRef>
<cautionRef id="c001" cautionIdentNumber="caution-001">
</cautionRef>
<cautionRef id="c002" cautionIdentNumber="caution-002">
</cautionRef>
</warningsAndCautionsRef>
<faultReporting>
<preliminaryRqmts>
<reqSafety>
<safetyRqmts cautionRefs="c001 c002" warningRefs="w001 w002"/>
</reqSafety>
</preliminaryRqmts>
</faultReporting>
</content>
</dmodule>
I would like to tokenize the attributes #cautionRefs (and #warningRefs) and then find the cautionRef element that matches its #id to the tokenized value:
<xsl:template match="#cautionRefs">
<xsl:for-each select="tokenize(.,'\s')">
<xsl:apply-templates select="//*[#id=.]"/>
</xsl:for-each>
</xsl:template>
but the apply-templates fails: Fatal error during transformation Leading '/' selects nothing: the context item is not a node. It works if I don't tokenize and use string functions instead but that is not desirable.
Desired result:
Tokenize #cautionRefs="c001 c002" (which has multiple parent elements)
So each value is passed to the <cautionRef>template that will retrieve the caution and warning statements, to be displayed in a PDF:
<xsl:apply-templates select="//*[#id='c001']"/>
<xsl:apply-templates select="//*[#id='c002']"/>
I tried using <xsl:key name="id" match="*" use="#id"/> with
<xsl:for-each select="key('id',tokenize(.,'\s'))">
but the for-each is blank.
The above apply-templates will match with this <cautionRef> template, which retrieves the caution and warning statements correctly. I just need help with the context of the #cautionRefs template:
<xsl:template match="cautionRef">
<xsl:variable name="IdentNumber" select="#cautionIdentNumber"/>
<xsl:apply-templates select="//cautionSpec[cautionIdent/#cautionIdentNumber=$IdentNumber]"/>
</xsl:template>
You could use a variable and use that for context:
<xsl:template match="#cautionRefs|#warningRefs">
<xsl:variable name="ctx" select="/"/>
<xsl:for-each select="tokenize(.,'\s')">
<xsl:apply-templates select="$ctx//*[#id=.]"/>
</xsl:for-each>
</xsl:template>
but I would use a key like you hinted at (updated to include context based on comments)...
<xsl:key name="by_id" match="*[#id]" use="#id"/>
<xsl:variable name="root" select="/"/>
<xsl:template match="#cautionRefs|#warningRefs">
<xsl:for-each select="tokenize(.,'\s')">
<xsl:apply-templates select="key('by_id',.,$root)"/>
</xsl:for-each>
</xsl:template>
Here's a full working example. NB it's best to have this level of detail in the actual question; i.e. a sample input file, the XSLT, and output, along with an example of what you want the output to look like.
Input:
<test>
<safetyRqmts cautionRefs="c001 c002" warningRefs="w001"/>
<cautionRef id="c001" cautionIdentNumber="caution-001"/>
<cautionRef id="c002" cautionIdentNumber="caution-001"/>
</test>
Stylesheet:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:template match="*|#*">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:key name="by_id" match="*[#id]" use="#id"/>
<xsl:template match="#cautionRefs|#warningRefs">
<xsl:apply-templates select="key('by_id', tokenize(.))"/>
</xsl:template>
</xsl:stylesheet>
Output:
<test>
<safetyRqmts><cautionRef id="c001" cautionIdentNumber="caution-001"/><cautionRef id="c002" cautionIdentNumber="caution-001"/></safetyRqmts>
<cautionRef id="c001" cautionIdentNumber="caution-001"/>
<cautionRef id="c002" cautionIdentNumber="caution-001"/>
</test>

XSLT: Copying node data to another node by matching attribute value, Efficiently?

I coded the XSLT to copy one node data to another by validating the attribute value, I got the desired output but I'm curious to know whether there is an efficient way to do this or if this is the only way to do it. [I'm not an XSLT expert] Can someone help !!!
Please use this link to check instantly.
https://xsltfiddle.liberty-development.net/pNvtBH2/3
Actual XML:
<?xml version="1.0" encoding="utf-8" ?>
<section>
<p>note 1 : 1</p>
<p>note 2 : 2</p>
<p>note 3 : 3</p>
<note id="test1">hello one</note>
<note id="test2">hello two</note>
<note id="test3">hello <i>three</i></note>
<note id="test4">hello <i>four</i></note>
</section>
Output:
<?xml version="1.0" encoding="UTF-8"?><section>
<p>note 1 : <a>hello one</a></p>
<p>note 2 : <a>hello two</a></p>
<p>note 3 : <a>hello <i>three</i></a></p>
<note id="test4">hello <i>four</i></note>
</section>
XSLT Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output method="xml" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="a">
<a>
<xsl:variable name="href" select="#href" />
<xsl:choose>
<xsl:when test="$href = //note/#id">
<xsl:copy-of select="//note[#id=$href]/node()" />
</xsl:when>
</xsl:choose>
</a>
</xsl:template>
<xsl:template match="note">
<xsl:choose>
<xsl:when test="#id = //a/#href">
<xsl:apply-templates select="node" />
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Whether it's efficient or not depends on how smart the optimizer in your XSLT processor is. Saxon-EE will do a pretty good job on this, Saxon-HE less so.
If you want to make it efficient on all processors, use keys. Replace an expression like //note[#id=$href] with a call on the key() function. Declare the key as
<xsl:key name="k" match="note" use="id"/>
and then you can get the matching nodes using key('k', $href).
The xsl:when test="$href = //note/#id" is redundant, as xsl:copy-of will do nothing if nothing is selected.
In the note template, I'm not sure what
<xsl:when test="#id = //a/#href">
<xsl:apply-templates select="node" />
</xsl:when>
is trying to achieve, because you don't have any elements named "node". If the aim is to avoid processing a note element at this stage if it was already processed from an a element, then you could build another index with
<xsl:key name="a" match="a" use="1"/>
and replace test="#id = //a/#href" with test="key('a', #href)"

XSLT List attributes in the order they appear in the xml file

I have a large number of xml files with a structure similar to the following, although they are far larger:
<?xml version="1.0" encoding="UTF-8"?>
<a a1="3.0" a2="ABC">
<b b1="P1" b2="123">first
</b>
<b b1="P2" b2="456" b3="xyz">second
</b>
</a>
I want to get the following output:
1|1|b1
1|2|b2
2|1|b1
2|2|b2
2|3|b3
where:
Field 1 is the sequence number for nodes /a/b
Field 2 is the sequence number of the attribute as it appears in the xml file
Field 3 is the attribute name (not value)
I don't quite know how to calculate field 2 correctly.
I've prepared the following xslt file:
<?xml version="1.0"?>
<xsl:stylesheet version="1.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="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:for-each select="a/b/#*">
<xsl:value-of select="count(../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text>
<!-- TODO: This is not correct -->
<xsl:value-of select="count(preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
but when I run the following command:
xsltproc a.xslt a.xml > a.csv
I get an incorrect output, as field 2 does not represent the attribute sequence number:
1|1|b1
1|1|b2
2|1|b1
2|1|b2
2|1|b3
Do you have any suggestions on how to get the correct output please?
Please notice that the answers provided in XSLT to order attributes do not provide a solution to this problem.
The order of attributes is irrelevant in XML. For instance, <a a1="3.0" a2="ABC"> and <a a1="3.0" a2="ABC"> are equivalent.
However this specific question is part of a larger application where it is essential to establish the order in which attributes appear in given xml files (and not in xml files that are equivalent to them).
Although, as kjhughes says in comments, attribute order is insignificant. However, you can still select them, and use the position() element to get the numbers you are after (You just can't be sure the order they are output will be the order they appear in the XML, although generally this will be the case).
Try this XSLT. Do note the nested use of xsl:for-each to select only b elements first, to get their position, before getting the attributes, which then have their own separate position.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:for-each select="a/b">
<xsl:variable name="bPosition" select="position()"/>
<xsl:for-each select="#*">
<xsl:value-of select="$bPosition"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="position()"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
You could use the position() of the items in the sequence of attributes that you are iterating over and combine with logic for the position of its parent element.
<xsl:template match="/">
<xsl:for-each select="a/b/#*">
<xsl:value-of select="count(../preceding-sibling::*)+1"/>
<xsl:text>|</xsl:text>
<!-- TODO: This is not correct -->
<xsl:value-of select="position() -
(if (count(../preceding-sibling::*)) then count(../preceding-sibling::*)+1 else 0)"/>
<xsl:text>|</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
Which produces the following output:
1|1|b1
1|2|b2
2|1|b1
2|2|b2
2|3|b3

XSL FO inline alignment on an existing sort/conditional XSL

I need to get right-align and left-align working in the same line. Looking over similar responses, I found the below recommendation,
<fo:block text-align-last="justify">
LEFT TEXT (want this to be the Contacts element from the below)
<fo:leader leader-pattern="space" />
RIGHT TEXT (want this to be the Address1 element from the below)
</fo:block>
But when I try to apply it to my existing XSL code (see below) I can’t make it work – I don’t know enough about how to edit it to accommodate/merge both the sort/conditionals and the FO. Can someone help me get this right?
Exsiting/working code:
<?xml version="1.0"?><!-- DWXMLSource="XML - Builder Members.xml" -->
<!DOCTYPE xsl:stylesheet [<!ENTITY nbsp " ">]>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="no"/>
<xsl:template match="/">
<memberdata>
<xsl:for-each select="memberdata/memberinfo">
<xsl:sort select="SortKey"/>
<memberdata>
<xsl:if test="Contacts[.!='']">
<Contacts><xsl:value-of select="Contacts" /></Contacts>
<xsl:text>
</xsl:text>
</xsl:if>
<xsl:if test="Address1[.!='']">
<Address1><xsl:value-of select="Address1" /></Address1>
<xsl:text>
</xsl:text>
</xsl:if>
</memberdata>
</xsl:for-each>
</memberdata>
</xsl:template>
</xsl:stylesheet>
Independently of the actual answer to your question (which is impossible to give in the current form the question is in), I'd like to suggest a few improvements to your general approach to XSLT:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="no"/>
<xsl:template match="memberdata">
<xsl:copy>
<xsl:apply-templates select="memberinfo">
<xsl:sort select="SortKey" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="memberinfo">
<memberdata>
<xsl:apply-templates select="Contacts" />
<xsl:apply-templates select="Address1" />
</memberdata>
</xsl:template>
<xsl:template match="Contacts|Address1">
<xsl:if test="normalize-space() != ''">
<xsl:copy-of select="." />
<xsl:text>
</xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Avoid <xsl:for-each>, use distinct templates and <xsl:apply-templates> instead. This results in cleaner, less duplicated and less deeply nested code. It also could result in more efficient processing of your stylesheet, as XSLT processors are optimized for template matching and can parallelize template execution.
Note that you can use the same template for multiple elements, see third template above.
Avoid adding line-breaks via such a construct: <xsl:text>
</xsl:text>. Doing this destroys source code readability and is prone to errors as soon as the source code is formatted (I've already done this in your question to be able to indent your code properly in the first place). Use character references
instead to separate source code layout and output layout.
Note that you can use <xsl:copy-of> to make a copy of an element, no need to do <foo><xsl:value-of select="foo" /></foo>.
Taking your request at face value, this seems to be what you're asking for, which merges the sort, the conditionals and the FO.
<?xml version="1.0"?><!-- DWXMLSource="XML - Builder Members.xml" -->
<!DOCTYPE xsl:stylesheet [<!ENTITY nbsp " ">]>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="no"/>
<xsl:template match="/">
<memberdata>
<xsl:for-each select="memberdata/memberinfo">
<xsl:sort select="SortKey"/>
<memberdata>
<fo:block text-align-last="justify">
<xsl:if test="Contacts[.!='']">
<Contacts><xsl:value-of select="Contacts" /></Contacts>
<xsl:text>
</xsl:text>
</xsl:if>
<fo:leader leader-pattern="space" />
<xsl:if test="Address1[.!='']">
<Address1><xsl:value-of select="Address1" /></Address1>
<xsl:text>
</xsl:text>
</xsl:if>
</fo:block>
</memberdata>
</xsl:for-each>
</memberdata>
</xsl:template>
</xsl:stylesheet>
However it seems unlikely that you really want to mix <fo:*> elements and other elements (<memberdata>) in your output... unless you plan to process them later to produce a full FO document. So the above may not be quite the solution you need.
(See also #Tomalak's good points about how to improve the XSLT. I would differ with him only on the question of for-each vs. apply-templates... it really depends on several factors and what your priorities are.)

Changing a namespace value in an XSL transformation?

I'm not sure if that is possible, as I'm very new to XSLT and stuff, but maybe some of you could help me here? It's a bit tricky and I haven't found anything like it on the internet:
The problem is that I have an input xml with namespaces declared and all and I only need to make slight changes to it (adding or deleting attributes, or shifting them to other locations). But at the same time, I have to update the namespace references in the document's document tag. So, for example, the input xml might look something like this:
<order
xmlns="some.url.01"
xmlns:ns2="some.other.url"
xmlns:ns3="another.one"
>
<orderEntry>
<orderControl>
<mandant>test</mandant>
<businessUnit>test</businessUnit>
<inboundChannel>test</inboundChannel>
<timestamp>timestamp</timestamp>
<requestedDocuments>
<ns2:document>orderForm</ns2:document>
</requestedDocuments>
</orderControl>
</orderEntry>
</order>
the resulting xml should look like this:
<order
xmlns="some.url.02"
xmlns:ns2="some.other.url.02"
xmlns:ns3="another.one.02"
>
<orderEntry>
<orderControl>
<mandant>test</mandant>
<businessUnit>test</businessUnit>
<inboundChannel>test</inboundChannel>
<!-- deleted timestamp for example -->
<requestedDocuments>
<ns2:document>orderForm</ns2:document>
</requestedDocuments>
</orderControl>
</orderEntry>
</order>
but the only thing I get is:
<order
xmlns="some.url.02"
>
<orderEntry>
<orderControl>
<mandant>test</mandant>
<businessUnit>test</businessUnit>
<inboundChannel>test</inboundChannel>
<!-- deleted timestamp for example -->
<requestedDocuments>
<ns2:document xmlns:ns2="some.other.url.02">orderForm</ns2:document>
</requestedDocuments>
</orderControl>
</orderEntry>
</order>
Now maybe for one or two of you it might not be that big a deal, but I have the restriction that the output document should look one-to-one the same as the input document except for the requested changes (namespace changes and deletion).
My XSLT looks a like this:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="some.url.02"
xmlns:ns2="some.other.url.02"
xmlns:ns3="another.one.02"
>
<xsl:output method="xml" version="1.0" encoding="UTF-8" standalone="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*">
<xsl:choose>
<xsl:when test="name(.) != 'timestamp'">
<xsl:element name="{node-name(.)}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{node-name(.)}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Can somebody please help? Namespaces are tricky :(
P.S.: Whoever edited my entry: Thanks :)
You can set the namespace on the output element with the namespace attribute:
<xsl:element name="{node-name(.)}" namespace="http://www.bar.org">
// ...
</xsl:element>
Note that the namespace must be a URI and although I expect you know this it's probably a good idea to use URIs in your example.
Here is a link to the excellent ZVON tutorial which has worked examples:
http://www.zvon.org/xxl/XSLTreference/Output/xslt_element_namespace.html
I agree that namespaces are tricky. As you know the prefix is semantically irrelevant, but many systems allow you to choose your prefix for aesthetic reasons. Also look at Saxon (http://saxon.sourceforge.net/)
EDIT I think you will find your answer here:
XSLT root tag namespace instead of element attribute namespace
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns1_src="some.url.01"
xmlns:ns2_src="some.other.url"
xmlns:ns3_src="another.one"
xmlns="some.url.02"
xmlns:ns2="some.other.url.02"
xmlns:ns3="another.one.02"
>
<!--
Note that all the source namespaces got their own new "*_src" prefix.
The target namespaces take over the original prefixes.
"some.url.02" is the new global namespace.
-->
<xsl:output method="xml" version="1.0" encoding="UTF-8" standalone="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- the identity template to copy everything, unless
it has been declared otherwise -->
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*" />
</xsl:copy>
</xsl:template>
<!-- three templates to handle elements -->
<xsl:template match="ns1_src:*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="node() | #*" />
</xsl:element>
</xsl:template>
<xsl:template match="ns2_src:*">
<xsl:element name="ns2:{local-name()}">
<xsl:apply-templates select="node() | #*" />
</xsl:element>
</xsl:template>
<xsl:template match="ns3_src:*">
<xsl:element name="ns3:{local-name()}">
<xsl:apply-templates select="node() | #*" />
</xsl:element>
</xsl:template>
<!-- three templates to handle attributes -->
<xsl:template match="#ns1_src:*">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<xsl:template match="#ns2_src:*">
<xsl:attribute name="ns2:{local-name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<xsl:template match="#ns3_src:*">
<xsl:attribute name="ns3:{local-name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<!-- timestamps will be ignored -->
<xsl:template match="ns1_src:timestamp" />
</xsl:stylesheet>
Output:
<order xmlns="some.url.02">
<orderEntry>
<orderControl>
<mandant>test</mandant>
<businessUnit>test</businessUnit>
<inboundChannel>test</inboundChannel>
<requestedDocuments>
<ns2:document xmlns:ns2="some.other.url.02">orderForm</ns2:document>
</requestedDocuments>
</orderControl>
</orderEntry>
</order>
<xsl:template match="a:*">
<xsl:element name="{local-name()}"
namespace="http://example.com/B">
<xsl:copy-of select="#*" />
<xsl:apply-templates />
</xsl:element>
</xsl:template>
It searches for any element in namespace with prefix a and replaces it with an element with the same name of namespace http://example.com/B. All attributes are copied 'as is' and then all children are evaluated.
Add your custom processing in or around that as needed.
Are you using Ant's XSLT task to do your transformation?
If the answer is yes, you may want to switch from the default XSLT engine that comes with Sun JDK 1.5+. Read this.
Also, read this article about namespaces in XSLT