Re: [xsl] Catch ALL | Failed template rule

Subject: Re: [xsl] Catch ALL | Failed template rule
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Tue, 22 Mar 2005 15:01:15 -0500
Karl,

What's confusing this issue is that templates only fire when they are matched, not when they fail to match.

This is relevant to the built-in rules (as Dimitre points out) since XSLT is designed so that no matter what a node is, there is some template that will match it. No node ever processed by an XSLT transformation ever "fails to match". Either it is selected for processing, or it isn't. If it's never selected it's immaterial what it would match if it were. If it is selected for processing, it will always match something: either an explicit template rule you have written, or a built-in template rule provided by the processor.

This is why a template with match="*" (match any child) or match="node()" (match any node) might be considered to be "catch all" templates -- because by design, they match nodes that other templates fail to match.

At 02:49 PM 3/22/2005, you wrote:
Transform XML into XML.  The resulting XML will be a series of pass
and fails where specific template rules have a match.  So you might be
asking questions like, does my element have an attribute "a" who's
value is "b"?  Or actually, you'd ask the question:  if my element has
an attribute "a" who's value is "b" then append the attribute "pass" =
"1" to the resulting XML, otherwise, append the attribute "pass" =
"0".

This is, in effect, a specification for a transform -- but notice it's able to say what values should be appended irrespective of whether nodes are matched by templates (as it should be). Notice that in order for an attribute pass="0" to be appended to nodes that didn't "pass", nodes to which it is to be appended have to be selected and processed in some way (and matching them with templates would be fine). That is, whether a node "passes" (and is marked as such), and whether it is matched by a template in the course of stylesheet processing, have nothing to do with each other.


Example XML:
<foo>
  <bar a="c"/>
  <bar a="b"/><!-- passes -->
  <bar a="a"/>
  <bar a="b"/><!-- passes -->
</abc>

You would then:
<xsl:apply-template select="foo/bar[@a='b']" mode="matchedresults"/>

And match on:
<xsl:template match="bar" mode="matchedresults">
  <!-- append element "pass" = "1"-->
</xsl:template>

At this point, there is no way to have an "unmatched" template result,
and this does make sense to me.

Right: not needed since nodes not of interest are simply not selected.


  I guess I was looking for the
cleanest way to exercise this.  I guess it would be this:
<xsl:apply-template select="not(foo/bar[@a='b'])" mode="unmatchedresults"/>

Having two different modes here is unnecessary (even apart from the fact that that XPath won't work). All you need is a modification of the identity transform:


<xsl:apply-templates select="foo/bar"/>

<xsl:template match="bar[@a='b']">
  <!-- this template matches bar elements you want to pass -->
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:attribute name="pass">1</xsl:attribute>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

<xsl:template match="bar[not(@a='b')]">
  <!-- this template matches bar elements you want not to pass -->
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:attribute name="pass">0</xsl:attribute>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

Cheers,
Wendell


====================================================================== 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 ======================================================================

Current Thread