This is the mail archive of the
xsl-list@mulberrytech.com
mailing list .
Re: template matches more than once
- To: Tom Power <TomP at AdvantageGroup dot co dot nz>
- Subject: Re: template matches more than once
- From: Jeni Tennison <jeni at friday dot u-net dot com>
- Date: Thu, 03 Aug 2000 20:42:34 +0100
- Cc: "'xsl-list at mulberrytech dot com'" <xsl-list at mulberrytech dot com>
- Reply-To: xsl-list at mulberrytech dot com
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