This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: template matches more than once


Tom,

This problem stems from applying templates to a larger set of nodes than
those you actually want to process.  In your root-matching template:

<xsl:template match="/">
  <HTML>
    <HEAD></HEAD>
    <BODY>
      <p>Select clause = //item - i.e. select all
	  item' elements in tree regardless of ancestry.</p>
      <xsl:apply-templates select="//item" />
    </BODY>
  </HTML>
</xsl:template>

you apply templates to *all* the item descendents of the root node (i.e.
all the item elements in the document).

You have a template that deals with those items for which the
@item_ParentID is '2':

<xsl:template match="item[@item_ParentID='2']">
  <p>
    <xsl:value-of select="@item_text" />
  </p>
</xsl:template>

But all the other item elements are processed by the built-in template:

<xsl:template match="*|/">
  <xsl:apply-templates/>
</xsl:template>

Your item elements are nested inside each other, so when your 'File' item
is processed by the built-in template, templates are applied to all its
children: the 'Save' and 'Documents' items.

So, the 'Save' and 'Documents' items are processed twice, once because they
are selected as descendent items of the root node, and once because they
are processed as children of the 'File' item.

There are three ways to solve this problem.

The first is to stop the built-in rule applying to the item elements that
you don't want to match by adding an item-matching template that does nothing:

<xsl:template match="item" />

The second is to take advantage of the built-in templates and change your
root-mode-matching template to process the first level of items, letting
the built-in templates process the children of these items until you get to
the items that you actually want to give some output for:

<xsl:template match="/">
  <HTML>
    <HEAD></HEAD>
    <BODY>
      <p>Select clause = //item - i.e. select all
	  item' elements in tree regardless of ancestry.</p>
      <xsl:apply-templates select="/menu/item" />
    </BODY>
  </HTML>
</xsl:template>

The third is to only process those items that you're actually interested in
in the first place and have a general item-matching template to give their
content:

<xsl:template match="/">
  <HTML>
    <HEAD></HEAD>
    <BODY>
      <p>Select clause = //item - i.e. select all
	  item' elements in tree regardless of ancestry.</p>
      <xsl:apply-templates select="//item[@item_ParentID='2']" />
    </BODY>
  </HTML>
</xsl:template>

<xsl:template match="item">
  <p>
    <xsl:value-of select="@item_text" />
  </p>
</xsl:template>

This latter is probably the most efficient because every time you apply
templates on a node it takes time to find the templates to be applied to
it: the fewer nodes you select to process, the less time it takes.

I hope this helps,

Jeni

Dr Jeni Tennison
Epistemics Ltd * Strelley Hall * Nottingham * NG8 6PE
tel: 0115 906 1301 * fax: 0115 906 1304 * email: jeni.tennison@epistemics.co.uk


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]