XSLT was designed from the start to transform trees into other trees. One type of tree that is easy to produce with XSLT is a well-formed HTML document, most often an XHTML document, which is a valid XML file that can also be displayed directly by web browsers. In this section, we will first show a simple selection of information from an XML file to produce tabulated information displayed as an XHTML page.
When the body of a template contains XML elements that are not XSLT elements (i.e. transformation instructions), they are copied verbatim to the output. So it is relatively easy to build the structure of an HTML document in which only some parts will be processed. This is similar in principle to the backquote macro processing in Lisp.
Selecting only red wines in our wine catalog (Example 2.3 (page )) and outputting an HTML table of a subset of the available information for each (Figure 5.1) can be done with the XSLT stylesheet given in Example 5.2.
Example 5.1. HTML tabular output of the red wines of the catalog produced by Example 5.2
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns:cat="http://www.iro.umontreal.ca/lapalme/wine-catalog" xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Wine Catalog</title> </head> <body> <h1> Wine Catalog (red only) </h1> <table border="1"> <tr> <th>Wine Name</th> <th>Code</th> <th>Color</th> <th>Year</th> <th>Price</th> <th>ml</th> <th>l</th> </tr> <tr> <td>Domaine de l'Île Margaux</td> <td>C00043125</td> <td>red</td> <td align="right">2002</td> <td align="right">$22.80</td> <td align="right">750</td> <td align="right">0.75</td> </tr> <tr> <td>Prado Rey Roble</td> <td>C00929026</td> <td>red</td> <td align="right">2002</td> <td align="right">$35.25</td> <td align="right">1500</td> <td align="right">1.5</td> </tr> </table> </body> </html>
The stylesheet in Example 5.2 first defines a template matching
the root node (line 14‑). Because the wine catalog is defined
in a specific namespace, its prefix must be declared (line 3‑
)
and used for selection. This template outputs the overall structure of the
XHTML file and then calls
xsl:apply-templates
to search for an appropriate template on
each child. In this case, it will correspond to cat:wine-catalog
. The corresponding template
(line 23‑) outputs a global heading and then starts a table and defines
its headers; the lines of the table will be filled by
selecting (line 35‑
) wines whose color property is
red
. To set up this color filter, a value must be assigned to the
code
variable either with an
xsl:variable
or
xsl:parameter
element. Here we chose the latter (line 6‑)
Since color is defined as a parameter of the
stylesheet, it is possible to change its value when the stylesheet is called by
the XSLT processor. The way of setting this value from outside the stylesheet
depends on each processor. In order for the
select
attribute value
to be the character string 'red'
and not the value associated with the
node red
(which is empty at this moment), single quotes must be added
within the double quotes indicating the value of the attribute. Note again the
use of the namespace prefix. The predicate used in square brackets limits the
nodes to which the templates will be applied but does not change the context of
the node, which is still the wine
node.
The output for each selected wine is defined with a template that is applied to each
cat:wine
. It outputs, on a single row of the table, the values of its
attributes, its color, its year (right aligned)
and formats its price to start with a dollar sign (right aligned). It finally outputs
the volume of each bottle in milliliters and in liters. Because the information in the
wine catalog is not given in milliliters, we call both a user-defined XPath
function (line 49‑) and a named
template (line 52‑
) to transform it appropriately. We
have deliberately chosen the same program structure in both the function and the named template to
highlight the differences and the similarities between these two means of organizing
computation in a stylesheet. Usually we will use functions to compute strings and
templates to produce elements, but the choice is left to the programmer.
Example 5.2. [WineCatalog.xsl
] XSLT stylesheet designed to select the red wines in the
catalog (Example 2.3) and to produce
Example 5.1 displayed as Figure 5.1
1 <?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:cat="http://www.iro.umontreal.ca/lapalme/wine-catalog"xmlns="http://www.w3.org/1999/xhtml" 5 version="2.0"> <xsl:param name="color" select="'red'"/>
<!-- to produce legal and validable XHTML ... --> <xsl:output method = "xml"
doctype-public = "-//W3C//DTD XHTML 1.0 Strict//EN" 10 doctype-system = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" indent = "yes" encoding = "UTF-8"/> <xsl:template match="/">
15 <html> <head><title>Wine Catalog</title></head> <body> <xsl:apply-templates/> </body> 20 </html> </xsl:template> <xsl:template match="cat:wine-catalog">
<h1> 25 Wine Catalog (<xsl:value-of select="$color"/> only) </h1> <table border="1"> <tr> <xsl:for-each
30 select="'Wine Name','Code','Color','Year','Price','ml','l'"> <th><xsl:value-of select="."/></th> </xsl:for-each> </tr> <xsl:apply-templates 35 select="cat:wine[cat:properties/cat:color=$color]"/>
</table> </xsl:template> <xsl:template match="cat:wine">
40 <tr> <td><xsl:value-of select="@name"/></td> <td><xsl:value-of select="@code"/></td> <td><xsl:value-of select="cat:properties/cat:color"/></td> <td align="right"><xsl:value-of select="cat:year"/></td> 45 <td align="right"> <xsl:value-of select="format-number(cat:price,'$0.00')"/> </td> <td align="right"> <xsl:value-of select="cat:toML(@format)"/>
50 </td> <td align="right"> <xsl:call-template name="toL">
<xsl:with-param name="fmt" select="@format"/> </xsl:call-template> 55 </td> </tr> </xsl:template> <xsl:function name="cat:toML">
60 <xsl:param name="fmt"/> <xsl:value-of select=" if ($fmt='375ml') then '375' else if ($fmt='750ml') then '750' else if ($fmt='1l') then '1000' 65 else if ($fmt='magnum') then '1500' else 'big'"/> </xsl:function> <xsl:template name="toL">
70 <xsl:param name="fmt"/> <xsl:choose> <xsl:when test="$fmt='375ml'">0.375</xsl:when> <xsl:when test="$fmt='750ml'">0.75</xsl:when> <xsl:when test="$fmt='1l'">1.0</xsl:when> 75 <xsl:when test="$fmt='magnum'">1.5</xsl:when> <xsl:otherwise>big</xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> 80
|
Definition of the |
|
Global parameter initialized with a string value; note the use of the
internal single quotes to make sure that the string value is used and
not a reference to a (non-existing) |
|
|
|
Template matching the root node that
defines the skeleton of the HTML page: a head and a body with a call to apply
templates on its children elements (only |
|
Template matching the catalog node to produce a header with a title and a table. The headings of the table are defined as the first row. The rest of the table will be filled with lines produced by each wine. |
|
Uses a |
|
Selects the wines with the chosen |
|
Outputs properties of a wine. The first
four are output as they appear in the source. The |
|
Outputs the bottle capacity, expressed in milliliters, using a
user-defined XPath function (line 59‑ |
|
Calls a named template that outputs the bottle capacity, expressed in liters. |
|
A user defined function which must be defined in a specific namespace
and that can be called within an XPath expression like any other
system defined one. Here we simply use a multi-line XPath
expression to select the appropriate case within a cascaded |
|
Definition of a named template in order to output the number of liters
corresponding to the value of the |
XSLT can also be used for more complex selections and transformations. We will now show how to create a web page presenting the content of the cellar and integrating information from the wine catalog. The end result is shown in Figure 5.2 (an outline of the underlying HTML code is shown in Example 5.3). There are external links in order to get more information about the wines by googling for the name of wine. There are two similar links for each wine but it is just to show and compare ways of creating them in XSL.
Example 5.3. HTML output by the XSLT code is shown in Example 5.4
This HTML code has been slightly reformatted and trimmed to fit on the page.
<html> <head> <title>Cellar of Jude Raisin</title> </head> <body> <h1>Cellar of Jude Raisin</h1> <table border="1"> <tr><th>...</th><th>...</th></tr> <tr> <td>...</td> <td>...</td> </tr> </table> <p/> <table border="1"> <tr><th>...</th><th>...</th><th>...</th> <th>...</th><th>...</th> </tr> <tr> <td>...</td> <td>...</td> <td align="right">...</td> <td align="center"/> <td align="right">...</td> </tr> ... <tr> <td colspan="3">...</td> <td align="right">...</td> <td align="right">...</td> </tr> </table> <h3>Comments</h3>C00043125 :<b>Guy Lapalme, Montréal</b>: should reorder soon<br/> C00312363 : Bottle too small...<br/> C00929026 :for <b>big</b> parties<br/> C10263859 :Really great<br/> </body> </html>
Example 5.4 illustrates some new features. The
root template (line 20‑) creates the high-level structure of the
XHTML file: the title of the page, also displayed at the top of the page,
refers to the name of the owner. In Example 2.2, element
name
(line 12‑) is structured in two elements:
first
and family
. When the value of such an element is
returned from an xsl:value-of
, it is the text content of all elements.
In fact, there are 5 parts in this case:
the text node comprising a \n
(this is the notation for an
end of line character) following the
name
opening tag and white space until the start of
first
the content of the element first
the \n
and spaces between the closing tag of first
and the
opening tag of family
the content of the element family
the \n
and spaces between the closing tag of family
and the closing
tag of name
Given the fact that a sequence of \n
and spaces in HTML is
displayed as a single space by the browser, we get an appropriate display in this
case. But this shows that handling text content can become a bit tricky. The
next section will explain how to work with some of the most frequent cases.
The content of the cellar book is obtained by an implicit
call to the template defined
on line 36‑ which creates a table with the address of the
owner (line 43‑
) and the
cellar (line 47‑
). It then calls the
cellar
template (line 54‑). The lines of the addresses are obtained by
looping on all elements with a
for-each
and outputting a
<br/>
between the text values of each element of the owner
and location
elements. Because we want to skip the first element (the
owner name has already been given at the top), we only keep
elements (line 43‑) with a position number greater than 1.
The cellar
(line 58‑) template produces a table of information about wines in the
cellar, sorted by their code. This is why the content of the
xsl:apply-templates
element (line 66‑) is an
xsl:sort
element indicating the sorting key and the sort order. The
last line of the table contains an estimated total value of the cellar obtained by a
call (line 73‑) to the
total
named template.
To compute the total number of bottles (line 79‑), we
can use the predefined
sum
function. Finally, if there are any comment in
the wine
elements of the cellar (line 84‑), we
add a
Comments
section and output each of them, also in increasing order of
wine code so that they are in the same order as in the table of wines.
We define the wine
template (line 95‑) to
create a row in the table of wines. In order to gather some
information about this wine from the wine catalog, we pass the wine node from the
wine catalog as a parameter to the call to the
nameAndUrl
template
(line 99‑). The link between the current element
and the corresponding element in the catalog is made using the value of the
code
variable given in the XPath expression. The remaining elements
of the row are the purchase date (right-aligned), a number of stars corresponding to the
rating and the quantity (right-aligned). The estimated value of the cellar is computed
using XPath expressions.
nameAndUrl
is a named template that receives a
wine
element as parameter. From this wine element, we create a
XHTML link (line 117‑) with an
a
element with
an href
attribute whose value is a string specifying the request to send to Google to search for this wine using
its name. This is a bit involved because the link must be created dynamically
using the the xsl:attribute
elements added to an enclosing a
element with
appropriate contents. For that, we use two variables:
$GoogleStart
xsl:param
for the whole stylesheet
(line 8‑$name
These values are used to create the value of the attribute href
of the a
element in the resulting HTML code.
Because creating such dynamic elements and attributes is often required, XSLT
designers have defined a non-XML formalism called Attribute
Value Template
in which we put braces around XPath expressions that denote values that will be evaluated
at run time and whose string value will replace the braces and their content
(line 127‑).
One should consult
the XSLT documentation to determine in which contexts this shortcut notation is allowed (it is indicated
by surrounding the content of the quotes by braces).
The comment
template (line 134‑) outputs the value of the
code
of the parent node, a colon and the text value of the comment followed by a line
break. In getting the content of the comment, the cat:bold
elements
will be processed by the appropriate template (line 142‑) that will
transform them in HTML
b
tags.
Example 5.4. [CellarBook.xsl
] XSLT stylesheet to produce information
about the cellar (Example 2.2). The resulting HTML code
(Example 5.3) is rendered as Figure 5.2.
1 <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:cat="http://www.iro.umontreal.ca/lapalme/wine-catalog" xmlns="http://www.w3.org/1999/xhtml" 5 version="2.0"> <!-- part of URL for a Google search --> <xsl:param name="GoogleStart">http://www.google.com/search?q=</xsl:param>10 <!-- to produce legal and validable XHTML ... --> <xsl:output method="xml" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" indent="yes" 15 encoding="UTF-8"/> <xsl:key name="catalog" match="cat:wine" use="@code"/>
<!-- matches the root node --> 20 <xsl:template match="/">
<html> <head> <title>Cellar of <xsl:value-of select="cellar-book/owner/name"/> 25 </title> </head> <body> <xsl:apply-templates/> </body> 30 </html> </xsl:template> <!-- output of the content of the cellar: addresses of the owner and cellar 35 followed by a table of wines --> <xsl:template match="cellar-book">
<h1>Cellar of <xsl:value-of select="owner/name"/></h1> <table border="1"> <tr> 40 <th>Personal address</th> <th>Cellar address</th> </tr> <tr><td><xsl:for-each select="owner/*[position()>1]">
<xsl:apply-templates/><br/> 45 </xsl:for-each> </td> <td><xsl:for-each select="location/*">
<xsl:apply-templates/><br/> </xsl:for-each> 50 </td> </tr> </table> <p/> <xsl:apply-templates select="cellar"/>
55 </xsl:template> <!-- content of the cellar as a table --> <xsl:template match="cellar">
<table border="1"> 60 <tr><!-- head of the table --> <xsl:for-each select="'Code','Name','Purchase Date','Rating','Nb bottles'"> <th><xsl:value-of select="."/></th> </xsl:for-each> 65 </tr> <xsl:apply-templates select="wine"><!-- each row -->
<xsl:sort select="@code" order="ascending"/> </xsl:apply-templates> <tr> 70 <td colspan="3">Estimated value</td> <td align="right"> <!-- compute the estimated value of the cellar --> <xsl:value-of select="
sum (for $w in wine return 75 $w/quantity * key('catalog',$w/@code)/cat:price)"/> </td> <td align="right"> <!-- compute the total number of bottles --> <xsl:value-of select="sum(wine/quantity)"/>
80 </td> </tr> </table> <!-- put comment section if at least one comment appears --> <xsl:if test="count(wine/comment)>0">
85 <h3>Comments</h3> <p> <xsl:apply-templates select="wine/comment"> <xsl:sort select="../@code" order="ascending"/> </xsl:apply-templates> 90 </p> </xsl:if> </xsl:template> <!-- information about a wine --> 95 <xsl:template match="wine">
<tr> <td><xsl:value-of select="substring(@code,2)"/></td> <td> <xsl:call-template name="nameAndUrl">
100 <xsl:with-param name="wine" select="key('catalog',@code)"/> </xsl:call-template> </td> <td align="right"><xsl:value-of select="purchaseDate"/></td> <td align="center"> 105 <xsl:value-of select="substring('*****',1,
if (rating/@stars) then rating/@stars else 0)"/></td> <td align="right"><xsl:value-of select="quantity"/></td> </tr> </xsl:template> 110 <!-- output the name of the wine with a link for "googling" it --> <xsl:template name="nameAndUrl">
<xsl:param name="wine"/> 115 <xsl:variable name="name" select="encode-for-uri($wine/@name)"/> <!-- dynamic creation of an element and its attributes --> <a>
<xsl:attribute name="href"> <xsl:value-of select="$GoogleStart"/> 120 <xsl:value-of select="$name"/> </xsl:attribute> <xsl:value-of select="$wine/@name"/> </a> <!-- link creation using an Attribute Value Template --> 125 <br/> <i> <a href="{$GoogleStart}{$name}">
<xsl:value-of select="$wine/@name"/> </a> 130 </i> </xsl:template> <!-- comment preceded by the code corresponding to it --> <xsl:template match="comment"><xsl:text>
135 </xsl:text> <xsl:value-of select="../@code"/> <xsl:text> : </xsl:text> <xsl:apply-templates/><br/> </xsl:template> 140 <!-- global change of <bold> tags to html <b> tags --> <xsl:template match="cat:bold">
<b><xsl:apply-templates/></b> </xsl:template> 145 </xsl:stylesheet>
|
Parameter giving the start of the URL allowing a search for a given wine on Google. |
|
Declaration of a key to access a wine element of the catalog use its |
|
Template for the root node that defines the skeleton the HTML page:
a head with a title indicating the name of the owner and a body to be filled by the application
of templates on the child element ( |
|
Global header with the name of the owner and then a table giving more information about the owner and the location of the cellar. |
|
Loop over all children nodes of the address, except the first one, the
name of the owner. After each node which will be output using the
default rules (only their text content will be output), a line break
is forced with an HTML |
|
Loop over all children nodes of the location. After each node which
will be output using the default rules (only their text content
will be output), a line break is forced with an HTML |
|
Outputs the content of the cellar with the appropriate template. |
|
The content of the cellar is given as a table with a header defined in this template, followed by a series of lines corresponding to each wine and finally a line holding the estimated value of the whole cellar. |
|
Applies the template for each wine but in increasing order of the
|
|
The total value of the cellar is computed using a relatively complex
XPath expression: that loops over all wines and returns the sum
of the value of each wine. The value of a wine is given by the number of
bottles ( |
|
The total number of bottles is the sum of the values of all
|
|
Comments appear at the bottom of the table if at least one wine
has a comment. They are also given in ascending order of |
|
Outputs a line of an HTML table for a given wine. |
|
Outputs the name of wine and its URL using
the named template defined on line 113‑ |
|
Outputs a string of |
|
Named template for outputting the name of the wine as the anchor text for an HTML link to Google with the appropriate wine name to get further information about it. We show here two alternative ways of creating the link. |
|
Creates an |
|
Creates an |
|
A comment is preceded with the value of the surrounding
|
|
A |
A observant reader might wonder where the text within a text element is coming
from, because there is no template in our program for this case. This output is
achieved by means a built-in XSLT template shown in Example 5.5
which stipulates at line 1‑ that
the content of text nodes and attributes are replaced by their string value. The built-in rule
for attribute nodes thus ignores their name.
Another built-in template for the document and element nodes, shown in line 5‑,
launches the application of templates on the children nodes thus traversing the document in a depth-first
manner (i.e. in document order). The combination of these two built-in rules explains why only the text
content of an XML document is displayed in a browser when no specific template is defined.
Example 5.5. [built-in-template-rules.xsl
] Built-in template rules for XSLT. These rules
are applied when no other defined template can be applied.
The previous examples showed transformations specific to a given XML file type. We now describe a transformation that can be applied to any XML file to show its indentation structure by means of nested HTML unnumbered lists.
Example 5.6. Excerpt of the HTML output (slightly reformatted here to fit in the page) produced by the transformation of Example 5.4 on the cellar book (Example 2.2).
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><title>HTML compaction of "CellarBook.xml"</title></head> <body> <ul><li><b>cellar-book</b> noNamespaceSchemaLocation="CellarBook.xsd"<ul> <li><b>wine-catalog</b> <ul><li><b>wine</b> name="Domaine de l'Île Margaux" appellation="Bordeaux supérieur" classification="a.c." code="C00043125" format="750ml" <ul><li><b>properties</b> <ul> <li><b>color</b> red</li> <li><b>alcoholic-strength</b> 12.5</li> <li><b>nature</b> still</li> </ul> </li> ... </ul></li> </ul></li> <li><b>owner</b><ul><li><b>name</b> <ul> <li><b>first</b> Jude</li> <li><b>family</b> Raisin</li> </ul> </li> ... </ul> </li> <li><b>location</b>...</li> <li><b>cellar</b> <ul><li><b>wine</b> code="C00043125"<ul> <li><b>purchaseDate</b> 2005-06-20</li> <li><b>quantity</b> 2</li> <li><b>comment</b> <ul> <li><b>bold</b> Guy Lapalme, Montréal</li> <li>: should reorder soon</li> </ul> </li></ul> </li> ... </ul> </li></ul></li></ul> </body> </html>
To transform the cellar book (Example 2.2) into the HTML code of Example 5.6 (rendered in Figure 5.3) we can use the code given in Example 5.7 which has four templates:
one matching the root element (line 17‑) that produces
the overall structure of the HTML file with its
head
and
body
elements. The processing of subelements
(line 25‑) is called within an unnumbered list
delimited by
ul
tags.
matching attributes (line 31‑) is done by outputting a
space (with an entity defined on line 3‑
), the name
of the
attribute followed by an equal sign and its value within double quotes.
elements (line 36‑) are transformed by
outputting the name of the element returned by the function
local-name()
in bold (line 38‑) followed
by its attributes. If the element is a node without any children
(line 41‑
) then it is output with only its content,
otherwise (line 44‑
) a new unnumbered list is started and
template matching is applied on children nodes
(line 46‑
).
text node content (line 53‑) is output within
li
tags.
The *
in the match
attribute (line 36‑)
indicates that this rule applies to all element nodes not matched by a more specific
rule such as the one on line 17‑
that matches only
the root node.
Example 5.7. [compactHTML.xsl
] XSLT transformation to produce a bulleted
outline (Example 5.6) from the cellar book
(Example 2.2)
1 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE stylesheet [ <!ENTITY space "<xsl:text> </xsl:text>">]> 5 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" version="2.0"> <xsl:strip-space elements="*"/>
10 <!-- to produce legal and validable XHTML ... --> <xsl:output method="xhtml" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" indent="yes"
15 encoding="UTF-8"/> <xsl:template match="/">
<html> <head> 20 <title>HTML compaction of
"<xsl:value-of select="replace(document-uri(.),'.*/(.*)','$1')"/>"</title> </head> <body> <ul> 25 <xsl:apply-templates/>
</ul> </body> </html> </xsl:template> 30 <xsl:template match="@*">
&space;<xsl:value-of select="local-name()"/> <xsl:text>="</xsl:text><xsl:value-of select="."/><xsl:text>"</xsl:text> </xsl:template> 35 <xsl:template match="*">
<li> <b><xsl:value-of select="local-name()"/></b>
<xsl:apply-templates select="@*"/> 40 <xsl:choose>
<xsl:when test="count(*)=0"> <!--single text node ?-->
&space;<xsl:value-of select="."/> </xsl:when> <xsl:otherwise> <!--possible mixed node-->
45 <ul> <xsl:apply-templates/>
</ul> </xsl:otherwise> </xsl:choose> 50 </li> </xsl:template> <xsl:template match="text()">
<li><xsl:value-of select="."/></li> 55 </xsl:template> </xsl:stylesheet>
|
Entity that corresponds to an explicit blank space. |
|
Ignores blank spaces in all elements. |
|
Makes sure that the output will be valid XHTML output. |
|
Matches the root node and produce the HTML skeleton. |
|
Outputs the title of the HTML page. Because the |
|
Start processing the root node of the document by applying the appropriate template. |
|
An attribute is output as a space (note the use of an entity to create an explicit text node that will not be ignored afterwards), the name of the attribute and its value between double quotes after an equal sign. |
|
An element node is a list-item. |
|
The name of the element in bold, followed by the attributes using the
template defined on line 31‑ |
|
The content of the element is output differently when it has children nodes or not. |
|
There are no children nodes, in our case this will only be a text node, its content is copied in the current list item. |
|
If there are children nodes, a new embedded unnumbered list is started. |
|
The templates are applied on all children nodes, this is the default
when no |
|
In the case of a text node within a list of children (i.e. a child of a mixed content element), it is output as list item. |