preload

XML/XSL Transformation: Using Sub-Templates

Posted by Albert Gareev on Mar 14, 2011 | Categories: ReportingSource codeXML Data

Parent page: Generating Test Reports

Today I continue with more complex examples using previously demonstrated XSL parsing nodes grouped into sub-templates.
Here’s our XML record simulating log data of a test session.

XML Source

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href=".\LogView2.xsl"?>
<log>
  <step type="#note">
    <time>21/04/2011 11:45:31 AM</time>
    <description>Typed data [User1234] in edit box [Username] </description>
  </step>
  <step type="#note">
    <time>21/04/2011 11:46:03 AM</time>
    <description>Typed data [Password1234] in edit box [Password]</description>
  </step>
  <step type="#bug">
    <time>21/04/2011 11:46:13 AM</time>
    <description>Edit box [Password] didn't accept [!@#$] chars</description>
  </step>
  <step type="#idea">
    <time>21/04/2011 11:46:37 AM</time>
    <description>Explore "Remember Me" functionality</description>
  </step>
  <step type="#note">
    <time>21/04/2011 11:47:01 AM</time>
    <description>Clicked on button [Login]</description>
  </step>
  <step type="#bug">
    <time>21/04/2011 11:47:22 AM</time>
    <flags screenshot="YES" />
    <screenshot>20111145_012852.jpg</screenshot>
    <description>Unfriendly error dialog</description>
  </step>
</log>

Note that the structure of XML file is not identical to the previous examples. It has more complexities and dependencies that need to be reflected in XSL file.

Did you notice the following line?

<?xml-stylesheet type=”text/xsl” href=”.\LogView2.xsl”?>

This is how we instruct the web browser to use XSL script for visualization of XML data.

Web-page Report

And here’s the source code of the script

XSL Source

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

<!-- variables -->
<xsl:variable name="CHAR_SPC">&#160;</xsl:variable>

<xsl:template match="/">

<html>

<head>
<title>automation-beyond.com | TestLog XML/XSL Transformation Example by Albert Gareev</title>
</head>

<body bgcolor="#c0c0c0">

<H1 align="center">Test Log</H1>
<H4 align="center">XML/XSL Transformation Example by <A HREF="http://automation-beyond.com/about/">Albert Gareev</A></H4>
<BR />
<P />
<h3 align="center">Test Steps</h3>
<BR />
<TABLE id="automation-beyond-2010" BORDER="1" width="650" align="center">
<TR>
  <TH width="150">Step Name</TH>
  <TH width="500">Step Description</TH>
</TR>

<xsl:for-each select="log/step">
  <xsl:choose>

    <xsl:when test = " @type = '#note' ">
      <xsl:call-template name="Display_Note" />
    </xsl:when>

    <xsl:when test = " @type = '#idea' ">
      <xsl:call-template name="Display_Idea" />
    </xsl:when>

    <xsl:when test = " @type = '#bug' ">
      <xsl:call-template name="Display_Bug" />
    </xsl:when>

    <xsl:otherwise>
      <TR>
        <TD>Error</TD>
        <TD>XML data error</TD>
     </TR>
    </xsl:otherwise>

  </xsl:choose>
</xsl:for-each>
</TABLE>
<BR />
<BR />
<BR />
<BR />

<div align="center">
<A HREF="http://automation-beyond.com/chapters/tutorials/test-reports/">Home</A>
</div>
<BR />

</body>

</html>
</xsl:template>

<!-- **************Sub-Templates****************************************** -->

<!-- **************Test Note****************************************** -->
<xsl:template name="Display_Note">
  <TR>
      <TD>
        <xsl:attribute name="title"><xsl:value-of select = "time" /></xsl:attribute>
        Test Note
      </TD>
      <TD><xsl:value-of select = "description" /><xsl:value-of select = "$CHAR_SPC" /></TD>
  </TR>
</xsl:template>

<!-- **************Test Idea****************************************** -->
<xsl:template name="Display_Idea">
  <TR>
      <TD>
        <xsl:attribute name="title"><xsl:value-of select = "time" /></xsl:attribute>
        Test Idea
      </TD>
      <TD><xsl:value-of select = "description" /><xsl:value-of select = "$CHAR_SPC" /></TD>
  </TR>
</xsl:template>

<!-- **************Logged Bug****************************************** -->
<xsl:template name="Display_Bug">
  <TR>
      <TD>
        <xsl:attribute name="title"><xsl:value-of select = "time" /></xsl:attribute>
        Bug
      </TD>

      <xsl:choose>
        <xsl:when test=" flags/@screenshot = 'YES' ">
          <TD>
 	      <xsl:attribute name="title">Click on the link to view the image attached</xsl:attribute>
	      <A TARGET="_blank">
		  <xsl:attribute name="href">
		    <xsl:value-of select="screenshot" />
		  </xsl:attribute>
              <xsl:value-of select = "description" />
  	      </A>
          </TD>
        </xsl:when>

        <xsl:otherwise>
          <TD><xsl:value-of select = "description" /><xsl:value-of select = "$CHAR_SPC" /></TD>
        </xsl:otherwise>
      </xsl:choose>

  </TR>
</xsl:template>
</xsl:stylesheet>

How To

  • Select type of XML node with xsl:choose
  • Define sub-templates with xsl:template outside of the main template
  • Call sub-templates with xsl:call-template

 

And here is the package containing the original XML and XSL files.


  • 3 responses to "XML/XSL Transformation: Using Sub-Templates"

  • Markus Gärtner
    14th March 2011 at 5:41

    Looking forward to a follow-up on parameters in calling named templates, and what to do if you don’t want to deal with named templates, or how to organize them with multiple inclusions.

    [ Albert’s reply.
    Hi, Markus.
    Yes, I do plan examples on calling sub-templates with parameters. However, I don’t think there is need to dig deeper into recursive transformations (yet it’s possible with XSL) in the scope of the current tutorial.
    Thanks.]

  • Inigo
    16th March 2011 at 13:48

    Your blogging software is broken. This is another attempt, with escaped angle brackets.

    [ Albert’s reply. Someone doesn’t like WordPress security measures… What can I say, be more polite, send an email (instead of providing a fake one), and I’ll consider publishing your code example. You indeed put an effort writing a lengthy comment. Thanks for that. ]

    You rarely need to use xsl:attribute – only if it’s conditional as to whether the attribute appears.

    [ Albert’s reply. Yes, that is what it’s going to be in some cases, but for others I will try your version. Thanks. ]

    You can get the same result as:

    <TD>
    <xsl:attribute name=”title”><xsl:value-of select = “time” /></xsl:attribute>

    with

    <TD title=”{time}”>

    and this is much more concise and readable.

    It’s almost always better to use xsl:apply-templates rather than xsl:for-each and named templates. For example, replace:

    <xsl:for-each select=”log/step”>
    <xsl:choose>
    <xsl:when test = ” @type = ‘#note’ “>
    <xsl:call-template name=”Display_Note” />
    </xsl:when>

    <xsl:when test = ” @type = ‘#idea’ “>
    <xsl:call-template name=”Display_Idea” />
    </xsl:when>

    etc.

    with

    <xsl:apply-templates select=”log/step”/>

    and then replace your named template for Display_Note with:

    <xsl:template match=”step[@type = ‘#note’]”>

    [ Albert’s reply. Nope. Not gonna work, because in the final version I use call parameters. ]

    This again makes the stylesheet more concise, and it puts the logic for when the template is applied within the template itself: this is more readable, and means only one place needs to be edited when you make changes.

    It also makes the stylesheet much easier to extend in future. If you wanted to have a similar stylesheet to the one above that adds an additional step type, then you would do it by importing that stylesheet with an xsl:import. Using the xsl:for-each approach as you have done, then you would then need to override the entire xsl:template match=”/”, or edit the original stylesheet. If you use the xsl:apply-templates approach, then you only need to add a single new template for your new step type.

    [ Albert’s reply. As I said, it’s not gonna work if you expand transformation functionalities. ]

    It looks like you’re using client-side XSLT within the browser, in which case you are constrained to only use XSLT 1. If that’s not the case, then you should definitely be using XSLT 2 – it’s much more powerful, and easier.

    [ Albert’s reply. Here you are right. It’s strictly a client side, local file in the most of cases. ]

  • Zack
    16th March 2011 at 22:42

    Just out of curiosity, is there a reason for choosing versus . Bonus: you can still call with parameters

    [ Albert’s reply. That was an exploratory example. I provided a working version. Give a sample of yours to benefit other readers. And I’ll look into it as well. ]

Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported
This work by Albert Gareev is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported.