Re: [xsl] match on attribute anywhere

Subject: Re: [xsl] match on attribute anywhere
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Thu, 14 Feb 2002 10:51:30 -0500
Andrew,

To complicate things a bit further,

At 07:38 PM 2/13/02, Chris wrote:
At 02:19 13-02-2002, Andrew Welch wrote:
>In my xml, if an element has an attribute 'mark=1' then it should be
>highlighted.  I can achieve it by putting a test on each template:
>
>However, doing this for each template seems a bit overkill, I would like to
>specify a general template like this:
>
><xsl:template match="@mark">
>         <span style="color:#FF0000">
>                 <xsl:apply-templates select/>
>         </span>
></xsl:template>
>
>and apply it using:
>
><xsl:apply-templates select="@mark|node()"/>
>
>This currently doesnt work for me - is it the correct approach?

First, you can't do <xsl:apply-templates select/>; in XML, you must have a
name and value for an attribute.  But even if you did <xsl:apply-templates
select="."/>, you'd be applying templates to the value of the mark
attribute, not to the content of the element that had the mark attribute.

Or more strictly, you'd be applying templates to the mark attribute itself, which given the fact you're now matching it, and that there's no mode, asks the template effectively to call itself, giving you an infinite loop.


What's going wrong here is that when you match the @mark attribute, you then proceed to create an element (the span), inside of which you need to proceed on down the tree; but you're also going down the tree after you've selected (or failed to select) the @mark. This means that when you have a @mark, you descend twice.

To avoid this, you can try something like

<xsl:template match="whatever">
  <span>
    <xsl:apply-templates select="@mark|node()"/>
  </span>
</xsl:template>

and then

<xsl:template match="@mark">
  <xsl:attribute name="style">color:#FF0000</xsl:attribute>
</xsl:template>

which seems like something more or less along the lines you were working.

But Chris's approach, while a bit more verbose, has the advantages of clarity of code, and not creating a span for *every* whatever, just those that have @mark attributes.

Cheers,
Wendell

The named template approaches were better, though I'm not sure they
directly addressed your problem.  Try this:

<xsl:template name="test-mark">
   <xsl:choose>
     <xsl:when test="@mark">
       <span style="color:#FF0000">
         <xsl:apply-templates/>
       </span>
     </xsl:when>
     <xsl:otherwise>
       <xsl:apply-templates/>
     </xsl:otherwise>
   </xsl:choose>
</xsl:template>

<xsl:template match="whatever">
   <xsl:call-template name="test-mark"/>
</xsl:template>


======================================================================
Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
Mulberry Technologies, Inc.                http://www.mulberrytech.com
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
----------------------------------------------------------------------
  Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================


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



Current Thread