I want to add a couple of elements at the end of an XML document, right before the closing of the root node, and I'm using an XSL to do the transformation.
The source XML can contain any node, subnode, etc, that doesn't matter. Everything in it should be copied to the transformed document, plus some other elements have to be added.
I'm totally new to XSL, XSLT and XPath, so I'm undoubtedly doing mistakes.
All my XSL's are like this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="yes" />
<!-- tried directives -->
</xsl:stylesheet>
This is what I found and tried, but with no success.
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
<my-el></my-el>
</xsl:template>
I've read that's the identity template, so I thought I'd use it to copy everything plus an additional element; but this adds <my-el></my-el>
inside each element of the source document.
After reading up a little of w3schools tutorials about XSLT and XPath, I tried with:
<xsl:template match="/">
<xsl:copy-of select="."></xsl:copy-of>
<my-elem />
</xsl:template>
But it adds <my-elem />
after the closing tag of the root element.
Can you help me out?
Background: I'm playing with the xml-maven-plugin
to add some configuration to a web application web.xml
file, triggered by a profile. I want that all of the existing XML in the file be copied to the output document, plus I want to add some (static will be enough for now) elements to it.
Here's the source web.xml
file:
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>My Project</display-name>
<welcome-file-list>
index.jsp
</welcome-file-list>
</web-app>
I want to achieve something like what's been asked in this question, but the new nodes have to be added to the root element (i.e. see a comment to that question answer).
Try it this way?
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- match the root element of unknown name -->
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<!-- add a new element at the end -->
<my-el>my content</my-el>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
If all you ever want to do is add the new element/s, then you could shorten this to:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- match the root element of unknown name -->
<xsl:template match="/*">
<xsl:copy>
<xsl:copy-of select="@*|node()"/>
<!-- add a new element at the end -->
<my-el>my content</my-el>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Note:
In your example input, the root element - and by inheritance, all of its child nodes - is in a namespace. If you want the added element/s to be in the same namespace, use:
<xsl:element name="my-el" namespace="{namespace-uri()}">my content</xsl:element>
instead of:
<my-el>my content</my-el>
Edit:
why doesn't it work if I put <xsl:template match="/web-app">
(<web-app/>
is the document root node) instead of <xsl:template match="/*">
?
That too is the result of the root element being in a namespace. In order to address it by name, you need to assign a prefix to the namespace and use it in the XPpath expression selecting the node:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:jve="http://java.sun.com/xml/ns/javaee"
exclude-result-prefixes="jve">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- match the root element of known name -->
<xsl:template match="/jve:web-app">
<xsl:copy>
<xsl:copy-of select="@*|node()"/>
<!-- add a new element at the end -->
<my-el>my content</my-el>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Once you have defined the prefix, you can also use it to place the added element/s in the namespace bound to the prefix:
<!-- add a new element at the end -->
<jve:my-el>my content</jve:my-el>
Alternatively you could do:
<!-- add a new element at the end -->
<my-el xmlns="http://java.sun.com/xml/ns/javaee">my content</my-el>