The impact of social media on the wine blogosphere

Wine Blog on Ulitzer

Subscribe to Wine Blog on Ulitzer: eMailAlertsEmail Alerts newslettersWeekly Newsletters
Get Wine Blog on Ulitzer: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Wine Authors: Jayaram Krishnaswamy, Rajeev Gupta, Mehdi Daoudi, OnPage Blog, Jyoti Bansal

Related Topics: Java Developer Magazine, Wine Blog on Ulitzer

Java Developer : Article

Stylesheet Debugging Tips

Stylesheet Debugging Tips

When your XSLT stylesheet doesn't do exactly what you want it to and you don't know why, what resources are available to figure it out? In other words, how do you debug a buggy stylesheet?

For now, I know of no XSLT equivalent to the kind of integrated debugger that's common with C++, Java, and Visual Basic development. These typically let you pause the execution of a program to allow a look at the values of specific variables at the stopping point and exactly which steps happened to lead to that point. Still, various XSLT coding tricks and features of certain processors can help do what these integrated debuggers do: let you know what's really going on in case a stylesheet doesn't behave the way you expected.

Runtime Messages, Aborting Processor Execution
The xsl:message instruction is supposed to send a message to somewhere other than the result tree. Exactly where depends on the processor; a command line processor typically displays the message only on the screen, even if the XSLT processor's output is redirected to a file. (Some processors, such as the msxml3.dll version of Microsoft's XML/XSLT processor, don't do anything with the xsl:message elements, so check your processor's documentation to see what to expect.)

Like the most primitive method of debugging in any language (that is, a lot of extra "print" statements outputting variable names and values during execution), the xsl:message instruction can be used to give some insight into the inner workings of your stylesheet.

For example, let's look at a stylesheet that converts this wine element to HTML.

<wine grape="Cabernet">
<winery>Duckpond</winery>
<product>Merit Selection</product>
<year>1996</year>
<price>11.99</price>
</wine>

The stylesheet has an xsl:message element inside an xsl:if element that lets the xsl:message instruction do its job only if the bodyTextSize parameter is set to something other than the default value. (Comments refer to each stylesheet's filename in the zip file where you can get the stylesheets and sample documents. Download the file at www.XML-Journal.com)

<!-- xq578.xsl: converts xq580.xml into xq583.html. -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html"/>
<xsl:param name="bodyTextSize">10pt</xsl:param>
<xsl:template match="/">
<xsl:if test="$bodyTextSize != '10pt'">
<xsl:message>bodyTextSize default value overridden
with value of <xsl:value-of select="$bodyTextSize"/>.
</xsl:message>
</xsl:if>
<xsl:apply-templates/>
</xsl:template>

<xsl:template match="winery">
<b><font size="{$bodyTextSize}"><xsl:apply-templates/>
<xsl:text> </xsl:text>
<xsl:value-of select="..[email protected]"/></font></b><br/>
</xsl:template>

<xsl:template match="product">
<i><font size="{$bodyTextSize}">
<xsl:apply-templates/></font></i><br/>
</xsl:template>

<xsl:template match="year | price">
<font size="{$bodyTextSize}"><xsl:apply-templates/></font><br/>
</xsl:template>

</xsl:stylesheet>

The following shows this stylesheet being run with the wine document above using the Sablotron XSLT processor. The stylesheet includes an xsl:param named bodyTextSize that is overridden at the command line with a value of "8pt":

C:\dat>sabcmd xq578.xsl xq580.xml $bodyTextSize=8pt > xq583.html

']
xsl:message (bodyTextSize default value overridden
with value of 8pt.
)
Because the bodyTextSize value is not "10pt" for this run of the stylesheet, the xsl:if instruction's test is true, so its contents get evaluated: an xsl:message instruction that sends the user a message about the default bodyTextSize value being overridden. Although the command line redirects the XSLT processor's output to a file called xq583.html, the message still appears on the screen. (Sablotron happens to enclose it in parentheses after some introductory text; other processors may handle it differently.) The xq583.html file was created without the message in it:
<font size="8pt">Duckpond Cabernet</font></b><br/>
<i><font size="8pt">Merit Selection</font></i><br/>
<font size="8pt">1996</font><br/>
<font size="8pt">11.99</font><br/>
The insertion of a parameter value ("8pt") in the text that the xsl:message instruction outputs shows how handy this element can be for reporting on the state of the system as the processor applies the stylesheet.

The xsl:message instruction's terminate attribute lets the stylesheet abort the execution of the processor. Its default value is "no"; the following stylesheet sets it to "yes." Except for the xsl:if instruction's test condition and the xsl:message element inside that xsl:if element, the stylesheet is identical to the previous one.

<!-- xq581.xsl: converts xq580.xml. -->

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">

<xsl:output method="html"/>

<xsl:param name="bodyTextSize">10pt</xsl:param>

<xsl:template match="/">
<xsl:if test="not(contains($bodyTextSize,'pt'))">
<xsl:message terminate="yes">bodyTextSize must be specified in points
(pt).</xsl:message>
</xsl:if>
<xsl:apply-templates/>
</xsl:template>

<xsl:template match="winery">
<b><font size="{$bodyTextSize}"><xsl:apply-templates/>
<xsl:text> </xsl:text>
<xsl:value-of select="..[email protected]"/></font></b><br/>
</xsl:template>

<xsl:template match="product">
<i><font size="{$bodyTextSize}">
<xsl:apply-templates/></font></i><br/>
</xsl:template>

<xsl:template match="year | price">
<font size="{$bodyTextSize}"><xsl:apply-templates/></font><br/>
</xsl:template>

</xsl:stylesheet>

The test condition in this stylesheet's xsl:if instruction uses the not() and contains() functions to check whether the value of bodyTextSize is missing the string "pt". If so, the message about the need to specify bodyTextSize in points is output, and because of the terminate value of "yes" in the xsl:message element, the XSLT processor halts after outputting the message.

C:\dat>sabcmd xq581.xsl xq580.xml $bodyTextSize=2feet > xq585.html
Error [code:255] [URI:file://C:/dat/xq581.xsl] [line:11]
[node:element '<xsl:message>']
xsl:message (bodyTextSize must be specified
in points (pt).) - terminating
The xq585.html file created by this command line is 0 bytes.

Despite XSLT's lack of interactivity, this ability to output messages about the state of the stylesheet's execution and even to halt that execution gives you a tool for checking what's going on under the hood when the results aren't what you expect. It also lets you make your stylesheets more bulletproof, because an application that can check whether something went wrong (especially something with the data) and then deliver a sensible message to the user about the problem is a much more robust application.

Keeping Track of Your Elements
As the size and complexity of your source documents and stylesheets get larger, there's more to keep track of and more potential for losing track of something. One technique for avoiding this is to make sure that every element type is accounted for in the stylesheet by never relying on the default template rules for processing elements.

As a sample source document to demonstrate the identification of elements that a stylesheet missed, we'll use the following document. Imagine that its chapter and appendix elements are much, much bigger and that there are many more of them than what is shown here.

<book>
<chapter><title>From Book I</title>
<para>Then with expanded wings he steers his flight</para>
<para>Aloft, incumbent on the dusky Air</para>
</chapter>

<chapter><title>More From Book I</title>
<para>For who can yet believe, though after loss</para>
<para>That all these puissant Leginos, whose exile</para>
</chapter>

<afterword>
<para>That was some poem, huh?</para>
</afterword>

<appendix><title>The Author</title>
<para>John Milton was born in London in 1608.</para>
<para>He died in 1674.</para>
</appendix>

<appendix><title>Glossary</title>
<para>puissant</para>
<para>Leginos</para>
</appendix>

</book>
The following stylesheet converts this document to an HTML file. Its first template rule covers all the element types that need no special handling, sending their contents to the result tree. In other words, it makes explicit what the default XSLT element-handling template rule makes implicit.
<!-- xq587.xsl: converts xq586.xml into xq588.html -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html"/>

<xsl:template match="chapter | appendix | afterword">
<xsl:apply-templates/>
</xsl:template>

<xsl:template match="*">
<h1><xsl:value-of select="name()"/> ELEMENT UNACCOUNTED
FOR BY STYLESHEET: <xsl:apply-templates/></h1>
</xsl:template>

<xsl:template match="book">
<html><body><xsl:apply-templates/></body></html>
</xsl:template>

<xsl:template match="title">
<h1><xsl:apply-templates/></h1>
</xsl:template>

<xsl:template match="chapter/para">
<p><font face="times"><xsl:apply-templates/></font></p>
</xsl:template>

<xsl:template match="appendix/para">
<p><font face="arial"><xsl:apply-templates/></font></p>
</xsl:template>

</xsl:stylesheet>

The second template rule overrides the default element handling rule by specifying "*" as its match condition. This template rule's job is to draw attention to any elements not addressed by any other template rules in the stylesheet. After an xsl:value-of instruction to add the stray element's name to the result tree, the template has a message to add to the result tree about why that template was called. The message is in all capital letters, and the whole thing is enclosed by an h1 element to really draw attention to the problem. (You wouldn't want a production version of your stylesheet creating such output; the xsl:message instruction described earlier is a better way to draw attention to something like this.) Running this stylesheet against the sample input shows that there was a para element that had no template to address it.

<html><body>
<h1>From Book I</h1>
<p><font face="times">Then with expanded wings he steers his
flight</font></p>
<p><font face="times">Aloft, incumbent on the dusky Air</font><p>

<h1>More From Book I</h1>
<p><font face="times">For who can yet believe, though after loss</font></p>
<p><font face="times">That all there puissant Leginos, whose exile</font><p>

<h1>para ELEMENT UNACCOUNTERD FOR BY STYLESHEET: That was some poem, huh?</h1>

<h1>The Author</h1>
<p><font face="arial">John Milton was born in London in
1608.</font></p>
<p><font face="arial">He died in 1674.</font></p>

<h1>Glossary<h1>
<p><font face="arial">puissant</font></p>
<p><font face="arial">Leginos</font></p>

</body></html>
Where was this para element? A quick glance at the source document would show that it was in the afterword element, but remember that we're pretending that this sample source document has many huge chapters and appendixes - it's too big to glance through quickly.

So how do we find the para element if we can't glance through the document? We know from looking at the stylesheet that it's not in a chapter element and it's not in an appendix element or the catchall template rule wouldn't have caught it. How can we find out this stray para element's ancestry? By listing out its ancestors.

The following template rule, when added to the previous stylesheet, lists the names of all the element types enclosing any para elements not caught by more specific template rules.

<!-- xq589.xsl: converts xq586.xml into xq590.html -->
<xsl:template match="para">
<h1>Unaccounted for para element</h1>
<h2>Ancestors</h2>
<xsl:for-each select="ancestor::*">
<xsl:value-of select="name()"/>
<xsl:if test="position() != last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>
<h2>Content</h2>
<xsl:apply-templates/>
</xsl:template>
Along with the para element's contents (under the h2 element at the end - when catching large elements, this might not be a good idea) and headers for the contents and ancestor list, this template has an xsl:for-each instruction that lists the names of all the nodes in the ancestor axis of the para element. (The template performs another nice trick along the way: instead of adding a comma after every element type name in the list, it adds commas after every one but the last one - the "position() != last()" condition prevents the last ancestor's name from getting the xsl:text node with the comma after it.)

The result shows that the para element's ancestors are book and afterword elements.

<html><body>
<h1>From Book I</h1>

<p><font face="times">Then with expanded wings he steers his flight</font></p>
<p><font face="times">Aloft, incumbent on the dusky Air</font></p>

<h1>More From Book I</h1>
<p><font face="times">For who can yet believe, though after loss</font></p>
<p><font face="times">That all these puissant Leginos, whose exile</font></p>

<h1>Unaccounted for para element</h1>
<h2>Ancestors</h2>
book, afterword
<h2>Content</h2>
That was some poem, huh?

<h1>The Author</h1>
<p><font face="arial">John Milton was born in London in
1608.</font></p>
<p><font face="arial">He died in 1674.</font></p>

<h1>Glossary</h1>
<p><font face="arial">puissant</font></p>
<p><font face="arial">Leginos</font></p>

</body></html>

With a more complex document, the ancestor list would be longer, and this template's usefulness would be more apparent. As with many debugging techniques, this is hardly worth the trouble when you can read through your entire program and input in a minute or two, but the larger your project, the more you'll appreciate this automated way to zero in on elements not caught by your stylesheet.

Tracing a Processor's Steps
The XSLT specification doesn't require XSLT processors to offer any features that let you trace their progress as they apply a stylesheet to a document, but many processors include these features anyway. When you release software whose job is to conform to a public standard (that is, to do the exact same things as other software in the same category), you want to offer something to get people to choose your software over the competition's; debugging features are an obvious choice.

These features can give you so much information about the XSLT processor's progress that it's easiest to demonstrate them with a short, simple stylesheet and short, simple source document. We'll apply this stylesheet:

<!-- xq594.xsl: converts xq595.xml into xq597.html -->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html"/>

<xsl:template match="story">
<html><body>
<xsl:apply-templates/></body></html>
</xsl:template>

<xsl:template match="title">
<h1><xsl:apply-templates/></h1>
</xsl:template>

<xsl:template match="para">
<p><xsl:apply-templates/></p>
</xsl:template>

</xsl:stylesheet>
to this document:
<story><title>Chapter 1</title>
<para>A Dungeon horrible, on all sides round</para>
<para>More unexpert, I boast not: them let those</para>
</story>
to create this result document:
<html>
<body>
<h1>Chapter</h1>
<p>A Dungeon horrible, on all sides round</p>
<p>More unexpert, I boast not: then let those</p>
</body>
</html>

To get a sample of what kind of extra debugging information XSLT processors may make available, this section looks at two processors: Xalan and Saxon. Most XSLT command line processors offer their own variation on this kind of debugging (or "trace") output; check the documentation of your own (or get Xalan and Saxon - they're both free).

Xalan's Java and C++ XSLT processors offer several command line switches to tell you different information about the processor's activity. The -TT switch tells the processor to trace the templates as they're being called. For the above stylesheet and source document, the following is the trace output:

Line #0, Column #0: xsl:template match="/"
Line #7, Column #31: xsl:template match="story"
Line #12, Column #31: xsl:template match="title"
Line #16, Column #30: xsl:template match="para"
Line #16, Column #30: xsl:template match="para"
It lists the name of each template and its location in the stylesheet as it gets called. As the first line shows, it even lists default templates when they're called; the stylesheet has no "/" template rule, so "Line #0, Column #0" refers to a default XSLT template.

Xalan's -TG switch traces each event generated by the reading of the input that the processor may react to:

STARTDOCUMENT
STARTELEMENT: html
STARTELEMENT: body
STARTELEMENT: h1
CHARACTERS: Chapter 1
ENDELEMENT: h1
IGNORABLEWHITESPACE
STARTELEMENT: p
CHARACTERS: A Dungeon horrible, on all sides round
ENDELEMENT: p
IGNORABLEWHITESPACE
STARTELEMENT: p
CHARACTERS: More unexpert, I boast not: them let those
ENDELEMENT: p
IGNORABLEWHITESPACE
ENDELEMENT: body
ENDELEMENT: html
It's a pretty complete listing of exactly what the processor sees in the source document, which can give you a clearer picture of why the processor is doing what it's doing.

The Saxon Java parser offers a -T option that sets a TraceListener class to output trace information. When used with the stylesheet and source document above, the following (with some carriage returns added) is only the beginning of the information it outputs.

<trace>
<Top-level element="xsl:output" line="5"
file="file:/home/dat/listing
s/xq594.xsl" precedence="0"/>
<Top-level element="xsl:template" line="7"
file="file:/home/dat/listings/xq594.xsl" precedence="0"/>
<Top-level element="xsl:template" line="12"
file="file:/home/dat/listings/xq594.xsl" precedence="0"/>
<Top-level element="xsl:template" line="16"
file="file:/home/dat/listings/xq594.xsl" precedence="0"/>
<Instruction element="xsl:output" line="5">
</Instruction> <!-- xsl:output -->
<Source node="/story[1]" line="1" mode="*default*">
<Instruction element="xsl:template" line="7">
<Instruction element="html" line="8">
<Instruction element="body" line="8">
<Instruction element="xsl:apply-templates" line="9">
<Source node="/story[1]/title[1]" line="1" mode="*default*">
<Instruction element="xsl:template" line="12">
In addition to being very detailed, this trace information is also well-formed XML, which means you can write XSLT stylesheets to do anything you want with it. Considering the level of detail available in this trace output, one obvious application of XSLT stylesheets to this information would be extracting and summarizing specific subsets of it.

The different trace output offered by different XSLT processors is a good reason to have more than one, especially if they're free. If you're frustrated by an unpredictable stylesheet, this may not be the best time to start learning about trace output options, wait 'til you have some time to play. Also, look for announcements of XSLT processor upgrades to check whether new forms of trace output are offered as a new feature.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.