codetoad.com
  ASP Shopping CartForum & BBS
  - all for $20 from CodeToad Plus!
  
  Home || ASP | ASP.Net | C++/C# | DHTML | HTML | Java | Javascript | Perl | VB | XML || CodeToad Plus! || Forums || RAM 
Search Site:



Previous Page  Page 1 Page 2 Page 3  Page 5 Page 6 Page 7 Page 8 Page 9 Page 10 Page 11 Next Page  

XSLT Processing Model

Templates in stylesheets each match particular nodes in the node tree. The match attribute on a template tells the XSLT processor what kind of nodes they match. In a full stylesheet, you tell the XSLT processor what nodes you want to be processed (using an <xsl:apply-templates> instruction, as you'll see later) and the XSLT processor goes through the nodes you've selected one by one trying to find a matching template for each in turn. When it looks for a template, it searches the whole stylesheet, so it doesn't matter where the template is within that stylesheet.

 

When the XSLT processor finds a matching template, it uses the content of that template to process the matching node and generate some output. The content of the template might include instructions that tell the processor to apply templates to a particular set of nodes, in which case it goes through those nodes finding and processing matching templates, and so on.

 

In this section, we'll look at the implications of this processing model and the kinds of changes that we can make to our stylesheet to take advantage of templates.

XSLT processing involves telling the processor to apply templates to some nodes in the source document. The XSLT processor locates a template that matches the node, and processes its content to generate a result. The location of the template within the stylesheet doesn't matter.

The Starting Template

This process of applying templates to nodes in the node tree has to start somewhere. In the majority of cases, the input to the stylesheet is an XML document, and the processor starts at the top of the node tree, on the root node. After building the node tree, the XSLT processor takes the root node and tries to find a template that matches it. If the XSLT processor finds one, it processes the content of that template to generate the output.

 

If you're running a stylesheet from code, then you can make the stylesheet start from a node other than the root node if you want. This is useful if you want to only process a section of a larger document, for example. In these cases, you need templates that match the nodes that you use as the source of the transformation – a template that matches the root node will only be used if you tell the processor to process the root node.

 

A template that matches the root node has a match attribute with a value of /, one that looks like:

 

<xsl:template match="/">

  ...

</xsl:template>

 

If you're familiar with programming, you can think of this template as analogous to the main() method on a class. Whatever happens, when you process a document with the stylesheet, the XSLT processor will process the contents of this template, so it gives you top-level control over what the stylesheet does.


 

If you look back at the full stylesheet that you created based on the simplified stylesheet from the last chapter, you'll see that it contains only one template, which matches the root node. The stylesheet works because the XSLT processor always activates that template.

A template that matches the root node acts as high-level control over the result of the stylesheet.

Matching Elements with Templates

At the moment, we use <xsl:for-each> to tell the XSLT processor to go through the <Channel> elements one by one. That's one place where we could use templates instead. In this section, we'll look at how we can replace this <xsl:for-each> with a separate template and an <xsl:apply-templates> instruction.

 

First, we need a template that tells the XSLT processor what to do when it's told to process a <Channel> element. You can match an element with a template by giving the name of the element in the match attribute of the <xsl:template> element. So the following template will match <Channel> elements and process them to generate the same result as is currently generated inside <xsl:for-each>:

 

<xsl:template match="Channel">

  <h2 class="channel"><xsl:value-of select="Name" /></h2>

  <xsl:for-each select="Program">

    <div>

      <p>

        <span class="date"><xsl:value-of select="Start" /></span><br />

        <span class="title"><xsl:value-of select="Series" /></span><br />

        <xsl:value-of select="Description" />

        <span onclick="toggle({Series}Cast);">[Cast]</span>

      </p>

      <div id="{Series}Cast" style="display: none;">

        <ul class="castlist">

          <xsl:for-each select="CastList/CastMember">

            <li>

              <span class="character">

                <xsl:value-of select="Character" />

              </span>

              <span class="actor">

                <xsl:value-of select="Actor" />

              </span>

            </li>

          </xsl:for-each>

        </ul>

      </div>

    </div>

  </xsl:for-each>

</xsl:template>


 

If a template's match attribute gives the name of an element, the XSLT processor will use that template for elements with that name.

You can put this template wherever you like at the top level of the stylesheet (at the same level as the other <xsl:template> elements). The XSLT processor will find it and use it whenever it needs to process a <Channel> element. In TVGuide3.xsl, I've put this template after the template that matches the root node, so the top level of the stylesheet looks like:

 

<?xml version="1.0" encoding="ISO-8859-1"?>

<xsl:stylesheet version="1.0"

                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 

<xsl:template match="/">

  ...

</xsl:template>

 

<xsl:template match="Channel">

  ...

</xsl:template>

 

</xsl:stylesheet>

 

I usually order the templates in my stylesheets starting from the template matching the root node and working down the levels of the node tree. But you are free to arrange your templates however you like.

 

However, the XSLT processor will never use this template unless you tell the processor to process (apply templates to) a <Channel> element. You instruct the XSLT processor to apply templates to some nodes using the <xsl:apply-templates> instruction. Like <xsl:for-each>, the result of the <xsl:apply-templates> instruction gets inserted into the result of the transformation at the point where you use the instruction, so while the location of <xsl:template> doesn't matter, the positioning of <xsl:apply-templates> is very important.

 

The <xsl:apply-templates> instruction has a select attribute, which tells the XSLT processor which nodes to apply templates to. The select attribute on <xsl:apply-templates> works in the same way as the select attribute on <xsl:for-each> – you give a path that points to the nodes to which you want to apply templates.

 

We want the result to appear at the same place as the result of the original <xsl:for-each>, and we already know the path to those nodes because we're already using it on the <xsl:for-each>. So you can apply templates instead by replacing the <xsl:for-each> with an <xsl:apply-templates> element that has exactly the same select attribute. Doing this in TVGuide4.xsl gives a template matching the root node as follows:

 

<xsl:template match="/">

  <html>

    <head>

      <title>TV Guide</title>

      ...


 

    </head>

    <body>

      <h1>TV Guide</h1>

      <xsl:apply-templates select="/TVGuide/Channel" />

    </body>

  </html>

</xsl:template>

 

Using templates instead of <xsl:for-each> breaks up the stylesheet into manageable chunks in a similar way to functions and methods in standard programming languages. One advantage of this is that you don't have XSLT with lots and lots of indentations, which can really help with readability! A bigger advantage is that you can use the same template for similar nodes in different places or on the same node multiple times, as we'll see later in the chapter. On the down side, the stylesheet no longer looks as similar to the HTML document that we're producing as it used to, and to change the result of the stylesheet, you may have to navigate between multiple templates.

You can replace an <xsl:for-each> element with a template holding its contents and an <xsl:apply-templates> element selecting the nodes you want to process.

Try It Out – Replacing <xsl:for-each> with Templates

We've still used <xsl:for-each> in a couple of other places within TVGuide4.xsl, so let's convert those instances in the same way as we've done with the one that iterated over <Channel> elements.

 

The next <xsl:for-each> is where we iterate over the <Program> elements, which is not within the template that matches <Channel> elements. We can convert it by first replacing the <xsl:for-each> with an <xsl:apply-templates> element that has the same value for its select attribute:

 

<xsl:template match="Channel">

  <h2 class="channel"><xsl:value-of select="Name" /></h2>

  <xsl:apply-templates select="Program" />

</xsl:template>

 

and then creating a template that matches <Program> elements. The new template has the same contents as the old <xsl:for-each> did:

 

<xsl:template match="Program">

  <div>

    <p>

      <span class="date"><xsl:value-of select="Start" /></span><br />

      <span class="title"><xsl:value-of select="Series" /></span><br />

      <xsl:value-of select="Description" />

      <span onclick="toggle({Series}Cast);">[Cast]</span>

    </p>

    <div id="{Series}Cast" style="display: none;">

      <ul class="castlist">

        <xsl:for-each select="CastList/CastMember">

          <li>


 

            <span class="character">

              <xsl:value-of select="Character" />

            </span>

            <span class="actor">

              <xsl:value-of select="Actor" />

            </span>

          </li>

        </xsl:for-each>

      </ul>

    </div>

  </div>

</xsl:template>

 

This template also contains an <xsl:for-each>, one that iterates over the <CastMember> element children of <CastList> elements. Again, we can replace this <xsl:for-each> with an <xsl:apply-templates>:

 

<xsl:template match="Program">

  <div>

    <p>

      <span class="date"><xsl:value-of select="Start" /></span><br />

      <span class="title"><xsl:value-of select="Series" /></span><br />

      <xsl:value-of select="Description" />

      <span onclick="toggle({Series}Cast);">[Cast]</span>

    </p>

    <div id="{Series}Cast" style="display: none;">

      <ul class="castlist">

        <xsl:apply-templates select="CastList/CastMember" />

      </ul>

    </div>

  </div>

</xsl:template>

 

and create a separate template that deals with giving output for <CastMember> elements:

 

<xsl:template match="CastMember">

  <li>

    <span class="character"><xsl:value-of select="Character" /></span>

    <span class="actor"><xsl:value-of select="Actor" /></span>

  </li>

</xsl:template>

 

We now have four templates in TVGuide5.xsl, matching:

 

        The root node

        <Channel> elements

        <Program> elements

        <CastMember> elements


 

If you run TVGuide5.xsl with TVGuide.xml, you should get exactly the same result as the original, simplified stylesheet. Splitting up the processing into separate templates hasn't changed the result of
the transformation.

Previous Page  Page 1 Page 2 Page 3  Page 5 Page 6 Page 7 Page 8 Page 9 Page 10 Page 11 Next Page  




Click here to Buy!

Buy Beginning XSLT here

© Copyright 2002 Wrox Press This chapter is written by Jeni Tennison and taken from "Beginning XSLT" published by Wrox Press Limited in June 2002; ISBN 1861005946; copyright © Wrox Press Limited 2002; all rights reserved.

No part of these chapters may be reproduced, stored in a retrieval system or transmitted in any form or by any means -- electronic, electrostatic, mechanical, photocopying, recording or otherwise -- without the prior written permission of the publisher, except in the case of brief quotations embodied in critical articles or reviews.











Recent Forum Threads
• Re: store string from text file to vector
• Re: c# .net Exception of type System.StackOverflowException was thrown.
• Re: error: expression must have a constant value
• Re: Script Does Folder Exist – If Not Create It
• $_GET not working
• GET METHOD
• Re: windows service - web service - com
• Re: Storing data from HTML to Excel or TXT
• Re: Help totalReads=1 totalReads++=2 write totalReads 3 not 2


Recent Articles
ASP GetTempName
Decode and Encode UTF-8
ASP GetFile
ASP FolderExists
ASP FileExists
ASP OpenTextFile
ASP FilesystemObject
ASP CreateFolder
ASP CreateTextFile
Javascript Get Selected Text


© Copyright codetoad.com 2001-2010