I have an XSL where I need to generate output along the lines of this:
<moo xmlns="http://api.example.com">
<foo>1358944586848</foo>
<bar>
<a>1</a>
<b>2</b>
<c>3</c>
</bar>
</moo>
I could do it like this:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://api.example.com">
<xsl:template match="/">
<xsl:element name="moo">
<!-- and so on -->
However, I kind of hate using the xsl prefix in my xsl files cause I feel it clutters it up a lot. Selecting with XPath is easy anyways since you can set xpath-default-namespace
to whatever you're transforming from if needed. But there is no element-default-namespace
available as far as I can see, so how can I generate the wanted output in a good way?
I know I can do this:
<stylesheet version="2.0"
xmlns="http://www.w3.org/1999/XSL/Transform">
<template match="/">
<element name="moo" namespace="http://api.example.com">
<!-- and so on -->
But then I have to set this namespace explicitly on every single element I create, or they will end up with the XSL namespace instead. So is there a clean way to create elements with a certain namespace (without a prefix) and not touching the default namespace of the xsl file?
Update:
Figured maybe namespace-alias
could do something, but can't figure out how to use it. Tried this, but doesn't seem to make any difference in the output at all:
<stylesheet version="2.0"
xmlns="http://www.w3.org/1999/XSL/Transform"
xmlns:out="http://api.example.com">
<namespace-alias stylesheet-prefix="out" result-prefix=""/>
<template match="/">
<element name="out:moo">
<!-- and so on -->
The namespace-alias
thing probably isn't doing what I think it is :p
The final solution I used, based on JLRishe's answer
remove-prefixes.xsl
<?xml version="1.0" encoding="UTF-8"?>
<stylesheet version="2.0" xmlns="http://www.w3.org/1999/XSL/Transform">
<template match="/">
<variable name="result">
<next-match />
</variable>
<apply-templates select="$result" mode="remove-prefixes" />
</template>
<template match="*" priority="1" mode="remove-prefixes">
<element name="{local-name()}" namespace="{namespace-uri()}">
<apply-templates select="@* | node()" mode="remove-prefixes" />
</element>
</template>
<template match="@*|node()" mode="remove-prefixes">
<copy>
<apply-templates select="@* | node()" mode="remove-prefixes" />
</copy>
</template>
</stylesheet>
subject.xsl
<!-- snip -->
<import href="remove-prefixes.xsl" />
<!-- snip -->
I feel the same way as you about the cluttering, especially if I have stylesheets where the overwhelming majority of elements is in the XSL namespace, not in the target namespace. The solution is simple: Give the output elements a prefix rather than the XSL elements:
One thing you could do is capture the entire result of the XSL in a variable, and then blank out its prefixes at the end:
When run on this input:
it produces:
The
xmlns:xsl
-approach is really the "standard" day, and I suppose that the designers of XSL had that in mind.Remember that you're allowed to directly mix XML fragments into XSL. From that point of view, your approach with the
xsl:element
arguably adds much more noise and clutter than what you are trying to eliminate with your "element-default-namespace".So, I'd do this:
Edit:
The following with
namespace-alias
might work:Or like this: