Very much a beginner with XSL. I'm trying transform 2 XML documents into a new XML document. I can't seem to get the tags to print to the new document. Only the content of the elements is printing.
XML
<books>
<book>
<name>Cat in the Hat</name>
<author>Me</name>
...
...
</book>
...
...
</book>
XSL
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method = "xml" indent = "yes" />
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:element name="books">
<xsl:template match="books">
<xsl:element name="book">
<xsl:for-each select="book">
<xsl:element name="name"><xsl:value-of select="name"/></xsl:element>
<xsl:element name="author"><xsl:value-of select="author"/></xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:element>
</xsl:stylesheet>
OUTPUT to XML file
Cat in the Hat
Me
I need the output to be:
<books>
<book>
<name>Cat in the Hat</name>
<author>Me</author>
</book>
</books>
What am I doing wrong?
Strictly speaking, you actually be getting an error when you run the output, as because MathiasMuller says in comments, xsl:element
must not be a top-level element (i.e it cannot be a direct child of xsl;stylesheet
). I am guessing Ecplise may just be ignoring that.
If you are, however, getting only text output, it is because of XSLT's built-in template rules, which will be used to match nodes in the XML when there are not any matching templates in your XML. Effectively these will just skip over elements, and end up outputting any text nodes they find.
If you do want to start off with the same output as the input (which is actually a sensible approach if ultimately you wish only to only change part of the XML), you should start off with the XSLT identity template, which on its own copies all nodes and attributes as-is (and will mean the built-in templates will not get used).
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:transform>
Then, when you want to make changes to the output, you only need to write templates for the nodes/attributes you wish to change. For example, suppose you had a date
element you wished to remove from under the book
element, then you would just add this template
<xsl:template match="date" />
Or maybe you want to rename name
to title
then you would do this
<xsl:template match="name">
<title>
<xsl:apply-templates select="@*|node()"/>
</title>
</xsl:template>
Note there is no real need to use xsl:element
if you are just outputting a fixed element name.