XSL output XML unprefixed without using default namespace?
I have XSL where I need to generate output line by line:
<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 hate using the xsl prefix in my xsl files because I feel like it gets in the way of it. Choosing with XPath is easy, as you can set xpath-default-namespace
what you are converting to if necessary. But as far as I know, no element-default-namespace
, so how can I generate the desired 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 have an XSL namespace instead. So, is there a clean way to create elements with a specific namespace (no prefix) and not touch the default namespace for the xsl file?
Update:
Maybe namespace-alias
can do something but can't figure out how to use it. Tried this but doesn't seem to make any difference in the output:
<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 -->
namespace-alias
thing probably doesn't do what i think: p
The last 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 -->
source to share
One thing you can do is grab the entire XSL result in a variable and then strip out its prefixes at the end:
<stylesheet version="2.0" xmlns="http://www.w3.org/1999/XSL/Transform"
xmlns:p="http://api.example.com">
<output method="xml" indent="yes"/>
<template match="/">
<variable name="result">
<p:moo>
<apply-templates />
</p:moo>
</variable>
<apply-templates select="$result" mode="removePrefix" />
</template>
<template match="root">
<p:something hello="hi">
<element name="p:somethingelse" />
</p:something>
</template>
<template match="p:*" mode="removePrefix">
<element name="{local-name()}" namespace="{namespace-uri()}">
<apply-templates select="@* | node()" mode="removePrefix" />
</element>
</template>
<template match="@* | node()" mode="removePrefix">
<copy>
<apply-templates select="@* | node()" />
</copy>
</template>
</stylesheet>
When run on this input:
<root>
<top />
</root>
it produces:
<moo xmlns="http://api.example.com">
<something hello="hi">
<somethingelse />
</something>
</moo>
source to share
xmlns:xsl
-approach is indeed a "standard" day, and I assume that the XSL developers had this in mind.
Remember, you are allowed to mix XML fragments into XSL directly. From this point of view, your approach with xsl:element
perhaps adds a lot more noise and clutter than what you are trying to eliminate with your default namespace.
So, I would do this:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://api.example.com">
<xsl:template match="/">
<moo>
<!-- and so on -->
Edit:
The following may work with namespace-alias
:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://api.example.com">
<namespace-alias stylesheet-prefix="xsl" result-prefix="#default"/>
<template match="/" xmlns="http://www.w3.org/1999/XSL/Transform">
<element name="moo">
<!-- etc -->
Or like this:
<stylesheet version="2.0"
exclude-result-prefixes="api"
xmlns="http://www.w3.org/1999/XSL/Transform"
xmlns:api="http://api.example.com">
<namespace-alias stylesheet-prefix="#default" result-prefix="api"/>
<template match="/">
<element name="moo">
<!-- etc -->
source to share
I feel the same way you do about clutter, especially if I have stylesheets where the vast majority of the elements are in the XSL namespace and not in the target namespace. The solution is simple: prefix the output elements, not the XSL elements:
<stylesheet version="2.0"
xmlns="http://www.w3.org/1999/XSL/Transform"
xmlns:o="http://api.example.com">
<template match="/">
<o:moo>
<!-- and so on -->
source to share