This document presents an XSL stylesheet to draw UPC/EAN barcodes, created by RenderX, Inc.. Similar techniques may facilitate deployment of XSL-based solutions in production environments where barcode labelling of documents is required.
Barcodes are very simple in physical structure - just rectangular black bars separated by white spaces. Representing such a structure in XSL Formatting Objects is easy, but a really challenging problem is to calculate bar widths starting from a string of symbols to encode. However, with XSLT, it becomes plausible. To confirm this claim, a stylesheet was designed to draw UPC/EAN barcodes.
UPC/EAN (Universal Product Code / European Article Numbering) is probably the most widespread barcode system: virtually every item found in stores bears a characteristic bars-and-digits label stamped on its back. EAN codes (8 and 13 digit) are used in all European countries, while UPC ones (8 and 12 digit) are more frequent in the North America. The encoding scheme for both barcode types is the same (12-digit UPC is a subset of 13-digit EAN).
Representation of digits by bars in UPC/EAN has some peculiarities:
An exhaustive description of the encoding algorithm can be found here.
No wonder that it took several hundred lines of XSLT code to get from a sequence of digits to the corresponding bar pattern. The result is a fairly complete XSL implementation of barcode drawing component. The stylesheet handles EAN codes (8-digit and 13-digit) and UPC codes (versions A and E). It provides for checksum calculation (including the trickiest UPC E case), and builds a complete pattern with numbers written at the bottom.
The stylesheet does more than just creating a sequence of bars: it also chooses the most traditional format for each type of code. There are subtle differences between EAN and UPC concerning digit grouping, bar lengths etc; all these are taken into account in the stylesheet.
Here is the stylesheet: barcode-EAN.xsl. Given below is a sample of its usage:
You can test it yourself:
<barcode>
item in bartest.xml;value
attribute of a newly created item;You can also try the barcode generator online:
The stylesheet barcode-EAN.xsl defines a named XSLT template
barcode-EAN
. It takes four parameters:
value
- a string of digits to encode (required).
Digits may be separated by spaces, commas, dots, dashes, or colons;
check digit should not be included.code-type
- one of EAN-13
, EAN-8
,
UPC-A
, or UPC-E
. If omitted, the template
tries to deduce the barcode type from the length of the string:module
- width of the narrow bar/space; default is 0.33 mm as required by the standard.height
- pattern height (= shortest bar length); default depends on the code type.To insert a barcode in your XSL FO document, place the following code in your stylesheet:
<xsl:import href="barcode-EAN.xsl"/> .... <xsl:call-template name="barcode-EAN"> <xsl:with-param name="value" select="'XXXXXXXX'"/> </xsl:call-template>
Here, 'XXXXXXXX'
stays for the number to encode as
a barcode. By specifying module
and height
parameters, you can control the appearance of the barcode pattern.
Please refer to comments in the body of the stylesheet for more
information.
(Note the single quotes around the parameter value: value type should be 'string'. If you insert an explicit value, you need an extra pair of quotes to protect this value from being treated as number; otherwise, leading zeros may result stripped).
Each barcode type expects the value
parameter to
contain a predefined number of digits:
The check digit (the last digit on the barcode labels) is not included in the argument - it will be calculated by the stylesheet itself.
The result of barcode template invocation will be an XSL FO table containing a sequence of bars, and a character string written below the bar sequence. Font size and padding of the bottom text is scaled proportionally to the pattern width. The table has an attribute that disables page breaks inside it, to prevent barcode image from accidental splitting.
Remember that tables in XSL FO are block-level elements; they cannot be included directly into a line of text. However, most practical applications require the barcode to be exactly positioned with respect to paper edges; this can be achieved by wrapping the table into an absolutely positioned block container.
The stylesheet uses an old (April 21, 99) version of XSL Formatting Objects (as used by XEP). However, changes required to bring it in conformance with the latest (March 27, 2000) XSL draft are minimal: you should change the namespace declaration on the root element and rename three properties:
n-columns-spanned
becomes number-columns-spanned
;n-rows-spanned
becomes number-rows-spanned
;page-break-inside="avoid"
becomes keep-together.within-column="always"
.The proposed technique has obvious advantages compared to other methods of including bar codes into XSL FO:
Naturally enough, this technique can be applied to other barcode systems as well. Besides UPC/EAN, we at RenderX have a working example of "Interleaved 2-of-5" barcode generator in XSL, available upon request.
In my opinion, this example demonstrates the strength of the "complete XSL" - the transformation part is used to implement a complicated algorithm, while the Formatting Objects are used to obtain a high-precision visual pattern.
Please write your comments/suggestions to Nikolai Grigoriev <grig@renderx.com>.