Re: [xsl] Re:Re: [xsl] XSLT/XPATH 2.0 - except example.

Subject: Re: [xsl] Re:Re: [xsl] XSLT/XPATH 2.0 - except example.
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Thu, 23 Jul 2009 18:01:24 -0400
Michel,

Using the modified identity method (and yes, it sounds like the right approach for you), yes it's pretty easy to leave an element in place but remove an attribute. It's also another useful lesson.

For your last problem, I suggested what you adapted as:

<xsl:template match="//xhtml:div[@class='center']">
  <xsl:copy>
    <xsl:copy-of select="@*"  copy-namespaces="no" />
    <xsl:apply-templates mode="remove"/>
  </xsl:copy>
</xsl:template>

This matches xhtml:div elements, copies them, copies their attributes to them, and applies templates to their children in the 'remove' mode.

If you want to remove that @class='center' attribute, you have two choices:

1. Remove it from the set of nodes (attributes) selected by the copy-of instruction.

For example, you now select "@*" (all attributes), where you could select "@* except @class" (all attributes except those named 'class') or "@* except @class[.='center']" (all attributes except those named 'class' with value 'center').

This is an effective but fairly quick and dirty method.

Method 2 builds on the notion of the recursive tree descent. It is a better solution when this is not the only modification you need to make. Instead of copying the attributes, you apply templates to them:

<xsl:template match="xhtml:div[@class='center']">
  <xsl:copy>
    <xsl:apply-templates select="@* | node()" mode="remove"/>
  </xsl:copy>
</xsl:template>

(Note I've removed the '//' from the match pattern. You never wanted that. It does nothing helpful and interferes with normal default processing in certain edge cases, so you shouldn't be in the habit of using it.)

This time there's no copy-of that copies the attributes. But attributes (@*) have now been added to the select expression on the apply-templates instruction. (You will also see "node()", which you need to apply templates to the children given that you're now selecting your nodes explicitly.)

Now we are applying templates to attributes, we are free to match them. So:

<xsl:template match="@*">
  <xsl:copy/>
</xsl:template>

... this will copy any attribute, and ...

<xsl:template match="xhtml:div/@class[.='center']"/>

... this will match @class attributes whose value is 'center' on xhtml:div elements, and do nothing. By overriding the other template, you are effectively preventing these attributes (only) from being copied.

You can write the same template to match "@class" to remove 'class' attributes from all elements in your source -- assuming the attributes are otherwise copied by matching them with templates. In other words, since template matching allows you to determine what level of specificity you want, it's an extremely flexible way of determining what gets copied and what doesn't (and not just copied but processed in any way whatsoever).

These two techniques fall into the categories called "pull" (method 1) and "push" (method 2) by XSLT developers. You could educate yourself on XSLT further by reading up on the topic.

It would be time well spent. These methods are at the core of what makes XSLT simple and powerful. Developers who don't know how to work with templates are like builders who don't know how to use power tools.

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