I have a template:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="urn:jboss:domain:1.1"
xmlns:d="urn:jboss:domain:1.1"
>
...
<xsl:template match="//d:interfaces/d:interface[#name='management']/d:inet-address">
...
</xsl:template>
This works.
<xsl:template match="//interfaces/interface[#name='management']/inet-address">
...
</xsl:template>
Why this doesn't work despite I have a default namespace set?
<xsl:template match="//interfaces/interface[#name='management']/inet-address">
...
</xsl:template>
Why this doesn't work despite I have a default namespace set?
This is one of the most FAQ on any XSLT and/or XPath list.
XPath treats any unprefixed name as belonging to "no namespace" -- regardless of the fact that there may be a default namespace defined and in scope.
To quote the W3C XPath 1.0 specification:
"A QName in the node test is expanded into an expanded-name using the
namespace declarations from the expression context. This is the same
way expansion is done for element type names in start and end-tags
except that the default namespace declared with xmlns is not used: if
the QName does not have a prefix, then the namespace URI is null"
Therefore the template rule above is matching elements that are in "no namespace", but the elements of the XML document are in the "urn:jboss:domain:1.1" namespace -- therefore not a single node is matched by the above rule.
Related
I am creating a quick-ref stylesheet for my XML files, and part of that reference is seeing which xml namespace I am using in each file.
For example, the start tage of gen_info.xml is:
<GeneralInfo xmlpre="Gen" xmlns="http://www.mrinitialman.com/">
Displaying the attribute "xmlpre" is easy enough: <xsl:value-of select="#xmlpre" /> . But <xsl:value-of select="#xmlns" /> seems to do nothing. What am I missing?
What am I missing?
You are missing the fact that xmlns="http://www.mrinitialman.com/" is not an attribute but a namespace declaration. It puts the GeneralInfo element and its descendants in a default namespace whose URI is "http://www.mrinitialman.com/".
You can use the namespace-uri() function to retrieve the namespace URI of a node. If - as it seems* - you are in the context of the GeneralInfo element, then:
<xsl:value-of select="namespace-uri()"/>
will return:
http://www.mrinitialman.com/
Note that an element can be in a namespace inherited from an ancestor element or determined by a prefix attached to its name; IOW, the namespace-uri() function returns the namespace URI of the argument node, not of a namespace declaration.
--
(*) It's not clear from your question how you get into the context of the GeneralInfo element, since it is in a namespace.
I need to generate the following output :
<x:Envelope xmlns:x='namespace1'>
<x:Root xmlns="namespace2">
<Header>
...
</Header>
</x:Root>
</x:Envelope>
I'm having trouble generating the default namespace for the x:Root element using xslt 1.0. I can get it to have no namespace ( but namespace2 will be specified on children of root - undesired behaviour ) or have it with a prefix :
<x:Root xmlns:x="namespace2">
but this fails schema validation. Any ideas ?
Edit : sorry for the ambiguous question and thanks for the answers. Root should be in namespace1 and Header should be in namespace2. However, the request is that namespace2 should not be declared in Header, but at Root level.
Regards,
It depends on how much of this is known statically. If you know everything statically, the literal result element
<x:Root xmlns="namespace2">..</x:Root>
will generate exactly what you want. In the more general case, you need to construct an element containing the required namespace node and then copy the namespace node:
<xsl:param name="ns">namespace2</xsl:param>
<xsl:variable name="temp">
<xsl:element name="dummy" namespace="{$ns}"/>
</xsl:variable>
...
<xsl:element name="Root">
<xsl:copy-of select="xx:node-set($temp)/namespace::*"/>
</xsl:element>
All so much easier in XSLT 2.0 with the xsl:namespace instruction.
You can't map two different namespaces to the same prefix "x". Instead, leave off the prefix for Root all together like this:
<Root xmlns="namespace2">
...
</Root>
I am trying to output the following line from an XSLT script. It is the first line just after xsl:template match="/". What I am trying to do is to transform XML document into an XML schema and need to output the xs:schema tag in particular way.
<xs:schema xmlns:ed="http://test1" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" targetNamespace="{$ns_name}" xmlns:tns="{$ns_name}" elementFormDefault="qualified" attributeFormDefault="unqualified" xsi:schemaLocation="http://test1 file://XmlSchemaAppinfo.xsd">
the $ns_name is a xsl:param name="ns_name". It is resolved in the targetNamespace="{$ns_name}" correctly but in the xmlns:tns="{$ns_name}" it is output literally
<xs:schema targetNamespace="akolodk" elementFormDefault="qualified" attributeFormDefault="unqualified" xsi:schemaLocation="http://test1 file://XmlSchemaAppinfo.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ed="test1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="{$ns_name}">
Namespace declarations are not treated the same as attributes, even though they look the same. The xmlns:tns will have been processed by the XML parser when the stylesheet was parsed, before it gets to the XSLT processor.
If you have XSLT 2.0 you can use
<xsl:namespace name="tns" select="$ns_name"/>
to create a namespace node in the result tree but there's no easy way I know of to generate a dynamic namespace in XSLT 1.0. You can't use xsl:attribute, the spec explicitly states that while
<xsl:attribute name="xmlns:xsl" namespace="whatever">http://www.w3.org/1999/XSL/Transform</xsl:attribute>
is not an error, it will generate an attribute, not a namespace declaration - the processor is required to ignore the xmlns prefix specified in the name and must use a different prefix to output the attribute.
If your processor supports the exslt node-set extension function then the following might work:
<xsd:schema .....>
<xsl:variable name="tnsElement">
<xsl:element name="tns:dummy" namespace="{$ns_name}"/>
</xsl:variable>
<xsl:copy-of select="exsl:node-set($tnsElement)/*/namespace::tns"/>
but again the processor is allowed to ignore the prefix of the xsl:element name attribute and use a different prefix bound to the same URI, you'll have to test it with your processor.
(and you'll have to add xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="exsl" to your xsl:stylesheet element).
In XSL only some attributes can be written using attribute value templates (using the '{}' notation). In particular, xmlns attributes do not support the notation.
I am using Sax transformer factory to do an XSLT transformation on large set of xsd files, so a particular line the xslt is as follows.
<xsl:result-document href="{$fileName}"
doctype-public="-//OASIS//DTD DITA Reference//EN"
doctype-system="reference.dtd">
<reference id="{$guid}" xml:lang="EN-US" outputclass="landscape">
<title>
<xsl:value-of select="$typeName"/>
</title>
<abstract>....
the reference tag being the root of the document, but the result has an unwanted xmlns:xsd attribute shown below.
...<reference xmlns:xsd="http://www.w3.org/2001/XMLSchema"
id="RANDOM-ID".....
this additional attribute is causing problems with parser that uses the transformed xml.
is this an issue with the XSLT or with SAXON api, how can i avoid this?
By default the xsl transformation will copy namespaces that are defined in the stylesheet to the output document. You can exclude this namespace by specifying the exclude-result-prefixes on the xsl:stylesheet or the reference element with a value of "xsd".
Here is the relevant part of the xslt sepcification:
The created element node will also have a copy of the namespace nodes that were present on the element node in the stylesheet (...)
A namespace URI is designated as an excluded namespace by using an exclude-result-prefixes attribute on an xsl:stylesheet element or an xsl:exclude-result-prefixes attribute on a literal result element. The value of both these attributes is a whitespace-separated list of namespace prefixes.
Greetings!
I want to extract some properties from different Maven POMs in a XSLT via the document function. The script itself works fine but the document function returns an empty result for the POM as long as I have the xmlns="http://maven.apache.org/POM/4.0.0" in the project tag. If I remove it, everything works fine.
Any idea how the make this work while leaving the xmlns attribute where it belongs or why this doesn't work with the attribute in place?
Here comes the relevant portion of my XSLT:
<xsl:template match="abcs">
<xsl:variable name="artifactCoordinate" select="abc"/>
<xsl:choose>
<xsl:when test="document(concat($artifactCoordinate,'-pom.xml'))">
<abc>
<ID><xsl:value-of select="$artifactCoordinate"/></ID>
<xsl:copy-of select="document(concat($artifactCoordinate,'-pom.xml'))/project/properties"/>
</abc>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">
Transformation failed: POM "<xsl:value-of select="concat($artifactCoordinate,'-pom.xml')"/>" doesn't exist.
</xsl:message>
</xsl:otherwise>
</xsl:choose>
And, for completeness, a POM extract with the "bad" attribute:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- ... -->
<properties>
<proalpha.version>[5.2a]</proalpha.version>
<proalpha.openedge.version>[10.1B]</proalpha.openedge.version>
<proalpha.optimierer.version>[1.1]</proalpha.optimierer.version>
<proalpha.sonic.version>[7.6.1]</proalpha.sonic.version>
</properties>
</project>
Your problem is that the POM extract uses default namespace. This means that the elements, although unprefixed, are in the "http://maven.apache.org/POM/4.0.0" -- not in the "no namespace".
However, in this XPath expression, in the XSLT code:
document(concat($artifactCoordinate,'-pom.xml'))/project/properties
the names project and properties are unprefixed. XPath always treats unprefixed names as belonging to "no namespace". Hence, no such elements are found and no node is selected.
Solution: Add a namespace definition to your <xsl:stylesheet>, lets say:
xmlns:p="http://maven.apache.org/POM/4.0.0"
Then rewrite element names in any expressions referencing POM nodes from someElement to p:someElement. For example:
document(concat($artifactCoordinate,'-pom.xml'))/p:project/p:properties
This is a namespace problem. The xmlns="http://maven.apache.org/POM/4.0.0" in the source document means that all the elements are by default put into the "http://maven.apache.org/POM/4.0.0" namespace in the XML document.
If you want to get ahold of them in your xslt, you need to declare that namespace in your xslt (with or without a prefix to use) and then use that namespace when selecting your elements.
For example, I'm guessing that the template in your example is meant to match an "abcs" element in your POM, yes? Try adding a namespace declaration in your xsl:stylesheet, e.g.:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:pom="http://maven.apache.org/POM/4.0.0" version="1.0">
That says to the XSL "I want to add 'pom' as a prefix that identifies the 'http://maven.apache.org/POM/4.0.0' namespace in this document."
Then when selecting elements or matching templates, use that prefix, e.g.:
<xsl:template match="pom:abcs">
Or try it without the prefixes by declaring your stylesheet with the POM namespace as default, something like:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://maven.apache.org/POM/4.0.0" version="1.0">
Node can (if using XSLT 2.0+) also be adressed via * because they lie in another namespace .
<xsl:copy-of select="document(concat($artifactCoordinate,'-pom.xml'))/*:project/*:properties)"/>
This can be just convienent or especially useful if the namespace is unknown. In this case the nice side effect is that if the namespace is marked this way the nodes from the other namespace don't get an annotation - which is not wanted in our case.