In below example which I found on this site, an empty xmlns="" gets copied in all child nodes. What can the reason be for this mistake?
My Template:
<xsl:element xmlns="http://www.element-examples.org" name="{local-name()}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
OUTPUT:
<projectgegevens xmlns="http://www.element-examples.org">
<idopdracht **xmlns=""**>28062262</idopdracht>
<projectcode **xmlns=""**>160622</projectcode>
<projectnaam **xmlns=""**>FF0000390001</projectnaam>
<ordernummer xmlns="">M2M-2022010071</ordernummer>
<projectleider xmlns="">FF000039003</projectleider>
<opmerking xmlns=""></opmerking>
<status xmlns="">5</status>
<datumverwacht xmlns="">2022-06-29</datumverwacht>
<certificaatnummer xmlns="">2020083810</certificaatnummer>
<analysemonsters xmlns="">
We can't tell you specifically what you did wrong without seeing all your code, but the namespace declaration xmlns="" is generated by the serializer when it finds that the result tree has an element in no namespace, whose parent is in a namespace (but with no prefix).
To find out why the child elements are in no namespace, rather than in the same namespace as their parent, you need to look at the XSLT code that creates the child elements. Note that the namespace of an element is determined entirely by the instruction that creates the element; it is never inherited automatically from the namespace of its parent element in the result tree (though it may be inherited from the parent element in the stylesheet).
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 have an XSLT key defined. I need to access the key from within a for-each loop, where that loop is processing a node-set that is outside the scope of where the key was defined.
Snippet, where I've marked two lines, one which works and one which does not:
<xsl:value-of select="key('name', 'use')"/> <!-- works -->
<xsl:for-each select="$outOfScopeNodeSet">
<xsl:value-of select="key('name', 'use')"/> <!-- does not work -->
</xsl:for-each>
Is there a way to access the key from within the for-each loop?
XSLT 1.0, msxsl engine.
(I could not think of a reasonable way to provide a full working example for this. I'm also not sure of the correct terminology, such as "scope" - perhaps if I knew the correct terminology I'd be able to find my answer already. If the question is not clear enough please let me know and I'll try to edit it into better shape.)
In XSLT 1.0, keys do not work across documents. It seems that your $outOfScopeNodeSet contains a node-set whose root node is different from the root node of the XML document being processed (probably created by the exsl:node-set() function?) - while the key is supposed to fetch a value from the processed XML document.
To resolve this problem, you need to return the context back to the processed XML document before calling the key() function, for example:
<xsl:variable name="root" select="/" />
<xsl:for-each select="$outOfScopeNodeSet">
<xsl:variable name="use" select="some-value" />
<xsl:for-each select="$root">
<xsl:value-of select="key('name', $use)"/>
</xsl:for-each>
</xsl:for-each>
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>
Is it possible to provide fallback behavior when a function implemented in an external XSLT object is not present (in XSLT 1.0)?
Right now, I have something similar to
<xsl:template match="an-element">
<xsl:value-of select="external-ns:ExternalFunction(.)" />
</xsl:template>
However, it's possible to generate content that makes sense if external-ns is not available, it just won't be as smart. So, I'd like to have something like
<!-- (pseudo) -->
<xsl:template match="an-element">
<xsl:try>
<xsl:value-of select="external-ns:ExternalFunction(.)" />
<xsl:catch>
<!-- do something else with the node -->
</xsl:catch>
</xsl:try>
</xsl:template>
I'm aware of xsl:fallback and element-available() but these seem to be only for elements, not functions. Is there any way to achieve this?
From http://www.w3.org/TR/xslt#function-function-available
Function: boolean function-available(string)
The argument must evaluate to a string
that is a QName. The QName is expanded
into an expanded-name using the
namespace declarations in scope for
the expression. The function-available
function returns true if and only if
the expanded-name is the name of a
function in the function library. If
the expanded-name has a non-null
namespace URI, then it refers to an
extension function; otherwise, it
refers to a function defined by XPath
or XSLT.
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.