At 2011-03-30 13:50 -0400, Costello, Roger L. wrote:
Hi Folks,
I want to transform this:
--------------------------------------------
<t:Test xmlns:t="http://www.test.org"
xmlns:unused="http://www.unused.org"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<t:faultcode>SOAP:client</t:faultcode>
</t:Test>
--------------------------------------------
to this:
------------------------------------
<Test xmlns="http://www.test.org"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<faultcode>SOAP:client</faultcode>
</Test>
------------------------------------
That is, I want to:
1. Replace namespace-qualified elements with a default namespace, e.g.,
Change this: <t:Test xmlns:t="..."
to this: <Test xmlns="..."
2. Delete unused namespace declarations, e.g.,
Delete this: xmlns:unused="..."
3. Retain a namespace declaration if it declares a namespace prefix
that is used in an element QName value, e.g.,
Retain this: xmlns:soap="..."
because the prefix is used in this element's value:
<faultcode>SOAP:client</faultcode>
The following template rule does (1) and (2) but fails to implement (3):
<xsl:template match="*[namespace-uri()]">
<xsl:element name="{local-name()}"
namespace="{namespace-uri()}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
Any ideas? I am using XSLT 1.0
First, you don't need to just match on elements with a
namespace-uri() because if there isn't one the code still works.
Second, it will slow down your transformation, and it isn't elegant
at all, but all you have to do is copy all descendent namespace nodes
that are not being used. The first step is to do this for elements
that are using the namespace except those using the parent's namespace:
<xsl:template match="*">
<xsl:element name="{local-name()}" namespace="{namespace-uri()}">
<xsl:for-each select=".//namespace::*">
<xsl:if test="(..//*)[namespace-uri()=current() and
namespace-uri()!=namespace-uri(current()/..)]
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
Then you have to modify that to include whatever test you need for
checking the name. You don't say how specific you need to be,
whether you are checking only <t:faultcode> elements or are you
checking all elements. The following checks all elements for
starting with the prefix ... I have no idea how specific you need to
be for poorly formatted text content (e.g. leading spaces):
<xsl:template match="*">
<xsl:element name="{local-name()}" namespace="{namespace-uri()}">
<xsl:for-each select=".//namespace::*">
<!-- ( ( find an element using the namespace but
not using the parent's namespace ) or
( find text content beginning with the namespace prefix ) )-->
<xsl:if test="(..//*)[namespace-uri()=current() and
namespace-uri()!=namespace-uri(current()/..)] or
(..|..//*)[starts-with(.,concat(name(current()),':'))]">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
Let the processor worry about cleaning up namespace declarations in the result.
BTW, although your input is XML well-formed, the prefix you use in
your text does not match the SOAP namespace declaration. I'll assume
that is an oversight and that you don't want to do case conversion
and that you would rather have the text as the same case as the
namespace prefix.
And, why are you bothered about superfluous namespaces? There is no
XML processing reason for getting rid of them.
And why restrict yourself to XSLT 1 when XSLT 2 can make this more succinct?
I hope this helps.
. . . . . . . . . Ken
~/t/ftemp $ cat roger.xml
<t:Test xmlns:t="http://www.test.org"
xmlns:unused="http://www.unused.org"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<t:faultcode>soap:client</t:faultcode>
</t:Test>
~/t/ftemp $ xslt roger.xml roger.xsl
<?xml version="1.0" encoding="utf-8"?><Test
xmlns="http://www.test.org"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<faultcode>soap:client</faultcode>
</Test>~/t/ftemp $
~/t/ftemp $ cat roger.xsl
<?xml version="1.0" encoding="US-ASCII"?>
<?xml-stylesheeta href="abc.xsl" type="text/xsl"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="@*|node()"><!--identity for all other nodes-->
<xsl:copy>
<xsl:copy-of select=".//namespace::*"/>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*" priority="1">
<xsl:element name="{local-name()}" namespace="{namespace-uri()}">
<xsl:for-each select=".//namespace::*">
<!-- ( ( find an element using the namespace but
not using the parent's namespace ) or
( find text content beginning with the namespace prefix ) )-->
<xsl:if test="(..//*)[namespace-uri()=current() and
namespace-uri()!=namespace-uri(current()/..)] or
(..|..//*)[starts-with(.,concat(name(current()),':'))]">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>~/t/ftemp $
--
Contact us for world-wide XML consulting & instructor-led training
Crane Softwrights Ltd. http://www.CraneSoftwrights.com/s/
G. Ken Holman mailto:gkholman(_at_)CraneSoftwrights(_dot_)com
Legal business disclaimers: http://www.CraneSoftwrights.com/legal
--~------------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--