Re: [xsl] Apply-templates - how to omit top level element tags?

Subject: Re: [xsl] Apply-templates - how to omit top level element tags?
From: Jon Gorman <jonathan.gorman@xxxxxxxxx>
Date: Thu, 8 Sep 2005 19:38:46 -0500
> Not so (I've just learned) when this is also part of the stylesheet:
>
>         <xsl:template match="@*|node()">
>                 <xsl:copy>
>                         <xsl:apply-templates select="@*|node()"/>
>                 </xsl:copy>
>         </xsl:template>
>
> Of course I didn't realize that until I had to produce a cut down
> version of the example to email you before.

And I was just going to comment on this template in your previous
email.  You may have figured it out already, but this template is the
primary part of what is called the identity transform.  It'll match
whenever there is not another template that matches a node and copy
that element and then process the children.  It's not as specific as
having a template that has match="Name", but will have the same
effect.

In this case, experience in my case shows rather than "skipping" the
node, you might just be better off having a generic

<xsl:template match="Name'>
<xsl:apply-templates />
</xsl:template>

If in what you want for most cases is for elements to be copied by
default.  (If not, yank that identity transform template out of
there.)

If you remove that template, I think you'll find most of the other
suggestions on the list also work.

> BTW, I think my comments are stepping on the toes of the "XSLT
> religion", for that I am sorry.  I am just a Secularist and try to apply
> critical thinking whenever possible, but of course I'm human so I'm
> still flawed.

I don't necessarily think that your comments are bother anyone.
Certainly they haven't bothered me.  It's just that a few of them are
misleading, such as "apply-templates" wouldn't work for you.  It's a
bit like saying you were using an object from a math library called
calculator and complained

calculator.sum(2,3)  didn't give you the right answer.

When somewhere above you had done calculator.base(4) and not told us about it

We of course were scratching our heads and saying that it will work.

Of course, I'm sure you have figured this out already.

Some other methods.

1) modes

I realize you don't like the idea of modes, but just for the archives,
and in case your cases
become more complex:



I'm not doing a perfect job.  I'm assuming anything not section is the
header.  You could do a better path that would say "get me all the
nodes before Sections occurs".
<xsl:template match="Guide">
<body>
<xsl:apply-templates mode="head" select="not(Sections)/>
<xsl:apply-templates mode="toc" select="Sections" />
<xsl:apply-template mode="content" select="Sections"/>
<xsl:apply-templates mode="footer" />
</body>
</xsl:template>
the folllowing are only the "Name" elements, but for the toc you'd
probably produce an ul and then apply-templates to all of it's
children, ect.

<xsl:template match="Name" mode="head">
<!-- if I had a dtd, I would use apply-templates without a mode to
essentially get the low level inline attributes -->
<h1><xsl:apply-templates /></h1>
</xsl:template>

<!-- I'm assuming each section has a name and some sort of unique
identifier-->
<xsl:template match="Name" mode="toc" >
<li><a href="#{@anchor}"><xsl:apply-templates /></a></li>
</xsl:template>

<xsl:template match="Name" mode="content">
<span style="title"><xsl:apply-templates /></span>
</xsl:template>

and generic,
<xsl:template match="Name">
<xsl:apply-templates />
</xsl:template>

2) Just call apply-templates selecting the name and having a template like
<xsl:template match="Name">
<xsl:apply-templates />
</xsl:template>

This means if you change your mind about the default, you only have to
change it in one place.

3) Call template (in this case it would be bad method, but people still use
it)
<xsl:call-template name="leaderTitle"/>

<xsl:template name="leaderTitle">
<xsl:for-each select="Name">
<h1><xsl:apply-templates /></h1>
</xsl:for-each>
</xsl:template>

The mode can be useful because you can "share" contexts.  That is, if
there are multiple elements that tend to appear multiple times in the
hierarchy but mean different things in those area they can all share
the same mode.  Think of it as a state machine of sorts.


> >> There are such ways: they're called template rules. Because in XSLT
> transformations the "entirely new context" is usually defined in
> relation to the input document, the primary (though not the only)
> mechanism for relating templates to their context of execution is the
> match pattern.
>
> I'm not familiar with XSLT "template rules"; is this a 2.0 concept?

Nope, ya know those match statements like "@*|node()"?  Those are
template rules, as defined by the XSLT spec, section 5.

Hmmm, from when I started this mail, saved the draft, and had dinner
there's been quite a few postings.  Perhaps I'll go read those
now...probably more than you wanted to know anyhow.  I think you're on
the right track.  I think XSLT handles the XML documents elegantly
enough.  I'm sure you could build it into some other framework if it
made you more comfy (something along the lines of SAX).  XSLT is more
than worth my while to learn, and I certainly would hate to have to
develop another system to handle XML that deals as nicely with it as
XSLT does.  (Well, ok I use SAX on occasion too, but not for the
complex narrative-centric files).

Jon Gorman

Current Thread