XML
<books>
<book title="XML Today" author="David Perry" release="2016"/>
<book title="XML and Microsoft" author="David Perry" release="2015"/>
<book title="XML Productivity" author="Jim Kim" release="2015"/>
</books>
The following XSL code iterates through all books by David Perry.
XSL
<xsl:key name="title-search" match="book" use="#author"/>
<xsl:template match="/">
<HTML>
<BODY>
<xsl:for-each select="key('title-search', 'David Perry')">
<DIV>
<xsl:value-of select="#title"/>
</DIV>
</xsl:for-each>
</BODY>
</HTML>
</xsl:template>
HTML output
<HTML>
<BODY>
<DIV>XML Today</DIV>
<DIV>XML and Microsoft</DIV>
</BODY>
</HTML>
Now I would like to iterate not only through all books by David Perry but through all books by any author.
How would a corresponding outer loop look like?
Or in other words: How do I iterate through all values of my title-search key.
The output should be something like this:
<HTML>
<BODY>
<H1>David Perry</H1>
<DIV>XML Today</DIV>
<DIV>XML and Microsoft</DIV>
<H1>Jim Kim</H1>
<DIV>XML Productivity</DIV>
</BODY>
</HTML>
This should do the job:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="title-search" match="book" use="#author"/>
<xsl:template match="/books">
<HTML>
<BODY>
<xsl:apply-templates select="book" />
</BODY>
</HTML>
</xsl:template>
<xsl:template match="book">
<xsl:variable name="author" select="#author" />
<xsl:if test="generate-id(.) = generate-id(key('title-search', $author)[1])">
<H1><xsl:value-of select="#author" /></H1>
<xsl:apply-templates select="//book[#author = $author]" mode="titles"/>
</xsl:if>
</xsl:template>
<xsl:template match="book" mode="titles">
<DIV>
<xsl:value-of select="#title"/>
</DIV>
</xsl:template>
</xsl:stylesheet>
It uses a technique called Muenchian grouping. Each element in an XML document implicitly has a unique ID assigned to it by the XSLT processor (it can also be explicitly assigned with the id attribute in the document itself). This part:
generate-id(.) = generate-id(key('title-search', $author)[1])
basically tests if the ID of the current book element is the same as that of the first book element with the same author. The variable $author is taken from the current book, The key is used to look up the <book> elements with that same author, the [1] predicate takes the first one. As a result, the <H1> is only generated for the first occurrence of that specific author, and in that same if element we're then applying the template for listing the books of that author. The mode is used to avoid a clash between these templates. There's no doubt a solution that doesn't use modes, but this works too. You could also do a lot of this with <xsl:for-each> but I made separate templates because XSLT is declarative and works best when treating it as such.
Grouping is a lot easier in XSLT 2, but when stuck with XSLT 1, the Muenchian grouping technique often provides a solution once you grok it.
Try this:
XSLT2:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<HTML>
<BODY>
<xsl:for-each-group select="books/book" group-by="#author">
<H1><xsl:value-of select="current-grouping-key()"/></H1>
<xsl:for-each select="current-group()">
<DIV><xsl:value-of select="#title"/></DIV>
</xsl:for-each>
</xsl:for-each-group>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
Related
EXAMPLE
Here is an example from MSDN. It show how to transform a XML file into HTML using xsl:key.
Example XML (input)
<books>
<book title="XML Today" author="David Perry" release="2016"/>
<book title="XML and Microsoft" author="David Perry" release="2015"/>
<book title="XML Productivity" author="Jim Kim" release="2015"/>
</books>
Example XSL (input)
<xsl:key name="title-search" match="book" use="#author"/>
<xsl:template match="/">
<HTML>
<BODY>
<xsl:for-each select="key('title-search', 'David Perry')">
<DIV>
<xsl:value-of select="#title"/>
</DIV>
</xsl:for-each>
</BODY>
</HTML>
</xsl:template>
Example HTML (output)
<HTML>
<BODY>
<DIV>XML Today</DIV>
<DIV>XML and Microsoft</DIV>
</BODY>
</HTML>
MY PROBLEM
I would like to produce the same HTML output but using a different XML input. How should the corresponding XSL file look like?
My XML (input)
<books>
<book>
<a n="author"><s>David Perry</s></a>
<a n="title"><s>XML Today</s></a>
<a n="release"><i>2016</i></a>
</book>
<book>
<a n="author"><s>David Perry</s></a>
<a n="title"><s>XML and Microsoft</s></a>
<a n="release"><i>2015</i></a>
</book>
<book>
<a n="author"><s>Jim Kim</s></a>
<a n="title"><s>XML Productivity</s></a>
<a n="release"><i>2015</i></a>
</book>
</books>
My XSL (input)
???
My HTML (output)
<HTML>
<BODY>
<DIV>XML Today</DIV>
<DIV>XML and Microsoft</DIV>
</BODY>
</HTML>
In the first example, your key matched book elements by their author attribute, but in the new XML, you want to match them by the a element where the n attribute is "author", so the key looks like this.
<xsl:key name="title-search" match="book" use="a[#n='author']/s"/>
Then, to get the title for the a matched book you would do this...
<xsl:value-of select="a[#n='title']/s"/>
Therefore your XSLT would look like this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" />
<xsl:key name="title-search" match="book" use="a[#n='author']/s"/>
<xsl:template match="/">
<HTML>
<BODY>
<xsl:for-each select="key('title-search', 'David Perry')">
<DIV>
<xsl:value-of select="a[#n='title']/s"/>
</DIV>
</xsl:for-each>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
You could actually drop the /s in the expressions here, if the s element was only ever going to be the only element under each a element.
This would work too:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" />
<xsl:key name="title-search" match="book" use="a[#n='author']"/>
<xsl:template match="/">
<HTML>
<BODY>
<xsl:for-each select="key('title-search', 'David Perry')">
<DIV>
<xsl:value-of select="a[#n='title']"/>
</DIV>
</xsl:for-each>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
This is basic XSLT transformation, you can do something like this:
<xsl:template match="book">
<div>
Author: <xsl:value-of select="a[#n='author']/s" />
title: <xsl:value-of select="a[#n='title']/s" >
release: <xsl:value-of select="a[#n='release']/s" >
</div>
</xsl:template>
I've the following XML.
<?xml version="1.0" encoding="UTF-8"?>
<docs>
<biblos>
<texto xmlns="http://www.aranzadi.es/namespace/contenido/biblos/texto" idioma="spa">
<parrafo>
<en-origen estilo-fuente="cursiva">This is cursive text.</en-origen>
</parrafo>
</texto>
</biblos>
</docs>
and the following XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<html>
<body>
<section class="chapter">
<xsl:apply-templates select="docs"/>
</section>
</body>
</html>
</xsl:template>
<xsl:template match="docs">
<div class="chapter">
<xsl:text>Docs Block</xsl:text>
<xsl:apply-templates select="biblos"/>
</div>
</xsl:template>
<xsl:template match="biblos">
<xsl:text>biblos block</xsl:text>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="texto">
<xsl:text>Text To Block</xsl:text>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="parrafo">
<div class="para">
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="parrafo">
<span class="format-smallcaps">
<xsl:apply-templates/>
</span>
</xsl:template>
<xsl:template match="en-origen">
<xsl:variable name="fontStyle">
<xsl:choose>
<xsl:when test="./#estilo-fuente">
<xsl:value-of select="concat('font-style-',#estilo-fuente)"/>
</xsl:when>
<xsl:when test="./#format">
<xsl:value-of select="concat('format-',#format)"/>
</xsl:when>
</xsl:choose>
</xsl:variable>
<span class="{$fontStyle}">
<xsl:value-of select="."/>
<xsl:apply-templates select="para"/>
</span>
</xsl:template>
</xsl:transform>
when i run this, I'm getting the below output.
<!DOCTYPE html
PUBLIC "XSLT-compat">
<html>
<body>
<section class="chapter">
<div class="chapter">Docs Blockbiblos block
This is cursive text.
</div>
</section>
</body>
</html>
Here the problem is, though I've declared texto and child nodes of it in my XSLT, it is not getting called, but the text is directly getting printed.
Please let me know where I'm going wrong and how I can fix it.
Good question (thanks for providing a complete, working example!). Often, if elements are not matched, the cause lies in missing namespaces:
You have the following in your input XML:
<texto xmlns="http://www.aranzadi.es/namespace/contenido/biblos/texto" idioma="spa">
In other words, the texto element is in a namespace. In your XSLT you have the following:
<xsl:template match="texto">
Since no namespace is declared for XPath (xpath-default-namespace on the containing xsl:template or xsl:stylesheet), this will operate on elements texto in no namespace, meaning, as written, it will not match texto from your source.
You can solve this by:
<xsl:transform
xmlns:tto="http://www.aranzadi.es/namespace/contenido/biblos/texto"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
and:
<xsl:template match="tto:texto">
Now your template will be matched.
Remember that element names can be in a namespace if the namespace is declared on that element, but the attributes, unless prefixes, are in no nammespace, so this solution is only required (given your example input) on matching or selecting elements.
Also, it is important to realize that prefixes do not matter, they do not need to match the prefix (or absence thereof) from the source document. What matters, is that the namespace bound to the prefix matches.
If there are child elements, in this case parrafo and en-origen, these inherit the namespace given on their parent element. So if you want to match these elements as well, you should adjust their names to tto:paraffo and tto:en-origin in patterns and XPath expressions.
I have to sort out the codes in numerical order.
The codes have four characters and four numerals.
for example,
COMP2100
COMP2400
COMP3410
LAWS2202
LAWS2250
when I just do <xsl:sort select="code" order="ascending" />
it displays above result.
However, I want that to be in 'numerical order' that is
COMP2100
LAWS2202
COMP2250
COMP2400
COMP3410
How do I do this?
Note: the OP has now provided sample XML. The below theories can be trivially adapted to this XML.
I. XSLT 1.0 (part 1)
Here is a simple solution that assumes your assertion ("the codes have four characters and four numerals") will always be the case:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:variable name="vNums" select="'1234567890'" />
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<t>
<xsl:apply-templates>
<xsl:sort select="substring(., 5)"
data-type="number" />
</xsl:apply-templates>
</t>
</xsl:template>
</xsl:stylesheet>
...is applied to an imagined XML document, shuffled into random order:
<?xml version="1.0" encoding="utf-8"?>
<t>
<i>COMP3410</i>
<i>LAWS2202</i>
<i>COMP2400</i>
<i>COMP2100</i>
<i>LAWS2250</i>
</t>
...the correct result is produced:
<?xml version="1.0" encoding="utf-8"?>
<t>
<i>COMP2100</i>
<i>LAWS2202</i>
<i>LAWS2250</i>
<i>COMP2400</i>
<i>COMP3410</i>
</t>
Explanation:
The Identity Transform -- one of the (if not the) most fundamental design patterns in XSLT -- copies all nodes from the source XML document to the result XML document as-is.
One template overrides the Identity Transform by sorting all children of <t> based upon the characters in the string from position 5 to the string's end.
Again, note that this solution assumes your original assertion -- "the codes have four characters and four numerals" -- is (and always will be) true.
II. XSLT 1.0 (part 2)
A (potentially) safer solution would be to assume that there might be numerous non-numeric characters in various positions within the <i> nodes. In that case, this XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:variable name="vNums" select="'1234567890'" />
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<t>
<xsl:apply-templates>
<xsl:sort select="translate(., translate(., $vNums, ''), '')"
data-type="number" />
</xsl:apply-templates>
</t>
</xsl:template>
</xsl:stylesheet>
...provides the same result:
<?xml version="1.0" encoding="utf-8"?>
<t>
<i>COMP2100</i>
<i>LAWS2202</i>
<i>LAWS2250</i>
<i>COMP2400</i>
<i>COMP3410</i>
</t>
Explanation:
The Identity Transform is once again used.
In this case, the additional template uses the so-called Double Translate Method (first proposed by Michael Kay and first shown to me by Dimitre Novatchev) to remove all non-numeric characters from the value of each <i> element before sorting.
III. XSLT 2.0 Solution
Here's a possible XSLT 2.0 solution is very similar to part 2 of the XSLT 1.0 solution; it merely replaces the Double Translate Method with XPath 2.0's ability to handle regular expressions:
<xsl:sort select="replace(., '[^\d]', '')" data-type="number" />
Note that by no means are you required to use regular expressions in XPath 2.0; the Double Translate Method works just as well as in XPath 1.0. The replace() method will, however, most likely be more efficient.
There are two obvious errors in the provided XSLT code:
The namespace used to select elements is different from the default namespace of the provided XML document. Just change: xmlns:xsi="file://Volumes/xxxxxxx/Assignment" to xmlns:xsi="file://Volumes/xxxxxxx/Assignment".
The sort at present is not numeric. Change:
<xsl:sort select="xsi:code" order="ascending" />
to:
<xsl:sort select="substring(xsi:code, 5)" data-type="number" />
The complete transformation becomes:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:xsi="file://Volumes/u4783938/Assignment">
<xsl:template match="/">
<html>
<head>
<title> Course Catalogue </title>
</head>
<body bgcolor="#FF9999">
<h1> <div style="text-align:center"> Course Catalogue </div> </h1>
<xsl:for-each select="xsi:catalogue/xsi:course">
<xsl:sort select="substring(xsi:code, 5)"
data-type="number" />
<div style="width:1000px;margin-bottom:4px;color:white;background-color:#F36;text-align:justify;border:outset;margin-left:auto;margin-right:auto;">
<xsl:apply-templates select="xsi:code" />
<br />
<xsl:apply-templates select="xsi:title" />
<br />
<xsl:apply-templates select="xsi:year" />
<br />
<xsl:apply-templates select="xsi:science" />
<br />
<xsl:apply-templates select="xsi:area" />
<br />
<xsl:apply-templates select="xsi:subject" />
<br />
<xsl:apply-templates select="xsi:updated" />
<br />
<xsl:apply-templates select="xsi:unit" />
<br />
<xsl:apply-templates select="xsi:description" />
<br />
<xsl:apply-templates select="xsi:outcomes" />
<br />
<xsl:apply-templates select="xsi:incompatibility" />
</div>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
and when applied on this XML document:
<catalogue xmlns="file://Volumes/u4783938/Assignment"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="file://Volumes/u4443554/Assignment/courses.xsd">
<course>
<code>ABCD3410</code>
<title> Information Technology in Electronic Commerce </title>
<year>later year</year>
<science>C</science>
<area> Research School of Computer Science </area>
<subject> Computer Science </subject>
<updated>2012-03-13T13:12:00</updated>
<unit>6</unit>
<description>Tce </description>
<outcomes>Up trCommerce. </outcomes>
<incompatibility>COMP1100</incompatibility>
</course>
<course>
<code>COMP2011</code>
<title> Course 2011 </title>
<year>Year 2011</year>
<science>C++</science>
<area> Research School of Computer Science </area>
<subject> Computer Science </subject>
<updated>2012-03-13T13:12:00</updated>
<unit>6</unit>
<description>Tce </description>
<outcomes>Up trCommerce. </outcomes>
<incompatibility>COMP1100</incompatibility>
</course>
</catalogue>
the produced result is now correctly sorted by the numeric part of the course code:
<html xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xsi="file://Volumes/u4783938/Assignment">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title> Course Catalogue </title>
</head>
<body bgcolor="#FF9999">
<h1>
<div style="text-align:center"> Course Catalogue </div>
</h1>
<div style="width:1000px;margin-bottom:4px;color:white;background-color:#F36;text-align:justify;border:outset;margin-left:auto;margin-right:auto;">COMP2011<br> Course 2011 <br>Year 2011<br>C++<br> Research School of Computer Science <br> Computer Science <br>2012-03-13T13:12:00<br>6<br>Tce <br>Up trCommerce. <br>COMP1100
</div>
<div style="width:1000px;margin-bottom:4px;color:white;background-color:#F36;text-align:justify;border:outset;margin-left:auto;margin-right:auto;">ABCD3410<br> Information Technology in Electronic Commerce <br>later year<br>C<br> Research School of Computer Science <br> Computer Science <br>2012-03-13T13:12:00<br>6<br>Tce <br>Up trCommerce. <br>COMP1100
</div>
</body>
</html>
I have question about XSLT1.0. The task is to write out in HTML all books written by given authors only by using XSL templates.
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book author="herbert">
<name>Dune</name>
</book>
<book author="herbert">
<name>Chapterhouse: Dune</name>
</book>
<book author="pullman">
<name>Lyras's Oxford</name>
</book>
<book author="pratchett">
<name>I Shall Wear Midnight</name>
</book>
<book author="pratchett">
<name>Going Postal</name>
</book>
<author id="pratchett"><name>Terry Pratchett</name></author>
<author id="herbert"><name>Frank Herbert</name></author>
<author id="pullman"><name>Philip Pullman</name></author>
</books>
So far I have this solution.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html"/>
<xsl:template match="/">
<html>
<head/>
<body>
<table border="1">
<xsl:apply-templates select="//author"/>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="author">
<tr>
<td>
<xsl:value-of select="name/text()"/>
</td>
<td>
<xsl:value-of select="#id"/>
</td>
<td>
<xsl:apply-templates select="/books/book[#id=#author]"/>
--previous XPath does not work properly, it should choose only those books that are written by the given author (that this template matches)
</td>
</tr>
</xsl:template>
<xsl:template match="book">
<xsl:value-of select="name/text()"/>
</xsl:template>
</xsl:stylesheet>
There is a problem though, explained in the comment.
Thank you Martin and Marzipan - it works now. There is one more thing. What if I wanted to have the book titles for each authors separated by commas? I propose this solution, but is there more elegant way to achieve this?
...
<xsl:apply-templates select="/books/book[current()/#id=#author][not(position()=last())]" mode="notLast"/>
<xsl:apply-templates select="/books/book[current()/#id=#author][last()]"/>
</td>
</tr>
</xsl:template>
<xsl:template match="book">
<xsl:value-of select="name/text()"/>
</xsl:template>
<xsl:template match="book" mode="notLast">
<xsl:value-of select="name/text()"/>
<xsl:text> , </xsl:text>
</xsl:template>
</xsl:stylesheet>
I just realized my question has been already answered by Marzipan. Quesion is solved then.
You want <xsl:apply-templates select="/books/book[current()/#id=#author]"/> or better yet a key (as a child of the xsl:stylesheet element):
<xsl:key name="book-by-author" match="books/book" use="#author"/>
and then <xsl:apply-templates select="key('book-by-author', #id)"/>.
The problem is this line:
<xsl:apply-templates select="/books/book[#id=#author]"/>
Understand that, when you enter a predicate, the context changes to the nodes matched by the preceding XPath selector. The context is no longer the node matched by the template it is within.
To get round this, commit the author's ID to a variable, then use that inside your predicate instead.
<xsl:variable name='author_id' select='#id' />
...
[#author=$author_id]
[EDIT - or, as Martin pointed out in his answer, use current() to force the context]
You can run it here:
http://www.xmlplayground.com/10FRcA
Is there any way to import stylesheets after checking some conditions?
Like,if the value of variable $a="1" then import 1.xsl or else import 2.xsl.
Hi All, Is there any way to import
stylesheets after checking some
conditions?
Like,if the value of variable $a="1"
then import 1.xsl or else import
2.xsl.
No, the <xsl:import> directive is only compile-time.
In XSLT 2.0 one can use the use-when attribute for a limited conditional compilation.
For example:
<xsl:import href="module-A.xsl"
use-when="system-property('xsl:vendor')='vendor-A'"/>
The limitations of the use-when attribute are that there is no dynamic context when the attribute is evaluated -- in particular that means that there are no in-scope variables defined.
A non-XSLT solution is to dynamically change the href attribute of the <xsl:import> declaration before the transformation is invoked:
Parse the xsl stylesheet as an XML file
Evaluate the condition that determines which stylesheet should be imported.
Set the value of the href attribute of the <xsl:import> declaration to the URI of the dynamically determined stylesheet-to-be-imported.
Invoke the transformation with the in-memory xsl stylesheet that was just modified.
I know this post is old, but I want to share my opinion.
Each display could use one template instead of two. The value display will be change with a VB application.
breakfast_menu.xml:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="conditionDisplay.xsl" ?>
<data>
<breakfast_menu>
<food>
<name>Belgian Waffles</name>
<price>$5.95</price>
<description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
<calories>650</calories>
</food>
<food>
<name>Strawberry Belgian Waffles</name>
<price>$7.95</price>
<description>Light Belgian waffles covered with strawberries and whipped cream</description>
<calories>900</calories>
</food>
<food>
<name>Homestyle Breakfast</name>
<price>$6.95</price>
<description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
<calories>950</calories>
</food>
</breakfast_menu>
<display>1</display>
</data>
In this file, I imported my displays and with a condition I tell the template what I need.
conditionDisplay.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:import href="display1.xsl"/>
<xsl:import href="display2.xsl"/>
<xsl:template match="/">
<xsl:variable name="display"><xsl:value-of select= "data/display"/></xsl:variable>
<xsl:choose>
<xsl:when test="$display='1'">
<xsl:call-template name="display1" />
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="display2 />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
display1.xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="display1">
<html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE">
<xsl:for-each select="data/breakfast_menu/food">
<div style="background-color:teal;color:white;padding:4px">
<span style="font-weight:bold"><xsl:value-of select="name"/> - </span>
<xsl:value-of select="price"/>
</div>
<div style="margin-left:20px;margin-bottom:1em;font-size:10pt">
<p>
<xsl:value-of select="description"/>
<span style="font-style:italic"> (<xsl:value-of select="calories"/> calories per serving)</span>
</p>
</div>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
display2.xsl:
<?xml version="1.0" encoding="UTF-8"?>futur
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="display2">
<html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<body style="font-family:Arial;font-size:12pt;background-color:#222222">
<xsl:for-each select="data/breakfast_menu/food">
<div style="background-color:teal;color:white;padding:4px">
<span style="font-weight:bold"><xsl:value-of select="name"/> - </span>
<xsl:value-of select="price"/>
</div>
<div style="margin-left:20px;margin-bottom:1em;font-size:10pt">
<p>
<xsl:value-of select="description"/>
<span style="font-style:italic"> (<xsl:value-of select="calories"/> calories per serving)</span>
</p>
</div>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
I genuinely apologize for my terrible English. It will be better to the next post and I hope will help someone as I think it's not the best solution.