Using XSLT to generate an invoice
Can use the XSLT Online Test Tool for the examples
This is a practical example of using XSL with a basic XML document. The XML document will have a few sections under an invoice root element. Company, Client, and Lineitems are the child elements.
<invoice>
<company>
<name> ACME </name>
<contact>W. Coyote </contact>
<email>coyotewe@acme.com</email>
</company>
<client>
<name> E. Fudd </name>
<email>efudd@domain.com</email>
<project>Wabbit Capture</project>
</client>
<lineitems>
<lineitem>
<description> Hunting </description>
<quantity>2</quantity>
<hourly>100</hourly>
<total>200</total>
</lineitem>
<lineitem>
<description> Tracking </description>
<quantity>1</quantity>
<hourly>100</hourly>
<total>100</total>
</lineitem>
</lineitems>
</invoice>
The XSLT document :
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
</xsl:template>
</xsl:stylesheet>
Let’s start by getting the data from the XML file. The XSL will match all nodes under the root element (invoice). These can be echoed by using the xsl:value-of-select() element. The attribute is an XPath expression for a node.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<h2><xsl:value-of select="//company/name"/></h2>
<h3><xsl:value-of select="//company/contact"/></h3>
</xsl:template>
</xsl:stylesheet>
The email field is to be displayed as an Anchor link. This requires some additional processing.
<xsl:variable name="hyperlink" select="//company/email"/>
<a href="mailto:{$hyperlink}"><xsl:text> contact </xsl:text></a>
Two new elements introduced are xsl:variable
and xsl:text
. xsl:text
is used to output plain text. Consider it the equivalent of echo or print in traditional programming languages. So far, only HTML elements have been added to the template. These do not require the xsl:text element. If text is placed inside of elements/tags, it does not need to use xsl:text
. It is only required for bare text.
xsl:variable
is how variables are assigned. The name
attribute is required and the select
attribute is optional. xsl:value-of select="expression"
could have been placed inside the xsl:attribute
tag. Simpler to just use select
. To use the variable, it must be enclosed in curly braces and start with a dollar sign. If the variable was not being assigned as an attribute of an element, it would have be required to use thexsl:value-of select="$variable"
format. Here’s an example :
<xsl:variable name="test">FOO</xsl:variable>
<xsl:value-of select="$test" />
Simple enough to replicate the same for the client section.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<h2><xsl:value-of select="//company/name"/></h2>
<h3><xsl:value-of select="//company/contact"/></h3>
<xsl:variable name="hyperlink" select="//company/email"/>
<a href="mailto:{$hyperlink}"><xsl:text> contact </xsl:text></a>
<h2><xsl:value-of select="//client/project"/></h2>
<h2><xsl:value-of select="//client/name"/></h2>
<xsl:variable name="clientemail" select="//client/email"/>
<a href="mailto:{$clientemail}"><xsl:text> email</xsl:text></a>
</xsl:template>
</xsl:stylesheet>
For the line items we need to loop through the items to output each line. This introduces the xsl:for-each
element.
<table>
<xsl:for-each select="//lineitems/lineitem">
<tr>
<td> <xsl:value-of select="description" /></td>
<td> <xsl:value-of select="quantity" /></td>
<td> <xsl:value-of select="hourly" /></td>
<td> <xsl:value-of select="total" /></td>
</tr>
</xsl:for-each>
</table>
To get a total we use xsl:value-of
and set the select
attribute to sum(expression)
.
<xsl:value-of select="sum(//lineitems/lineitem/total)" />
The final table code :
<table>
<xsl:for-each select="//lineitems/lineitem">
<tr>
<td> <xsl:value-of select="description" /></td>
<td> <xsl:value-of select="quantity" /></td>
<td> <xsl:value-of select="hourly" /></td>
<td> <xsl:value-of select="total" /></td>
</tr>
</xsl:for-each>
<tr>
<td />
<td><xsl:text>Total</xsl:text> </td>
<td>
<xsl:value-of select="sum(//lineitems/lineitem/total)" />
</td>
</tr>
</table>
That completes the processing for the invoice. It’s just plain html and the layout isn’t particularly useful.
Can add standard HTML tags and move the XSL elements to produce a much cleaner looking final document.
CSS can be linked using LINK
as usual.