(I sent this before but for some reason it seems to have been lost --
apologies if it turns up twice.)
Ben,
As so often, the problem here is in the specification.
You have solved the problems of removing elements according to one rule:
1. elements that have no content (child nodes)
and of attributes according to another:
2. attributes that have no value
but not of removing elements defined as "empty" according to a third:
3. elements that contain only elements and attributes that would
removed (by any rule).
You do infer that since your third rule is recursive, a full solution
will also be recursive.
If you can rewrite rule 3 so it doesn't invoke itself, you can write
a transform that doesn't have to process its own results recursively.
For example, you might say:
3a. elements none of whose attributes have values and whose children
are empty (have no children)
-- but of course 3a will fail if your containment of such elements
goes deeper than two.
Here's a recursive solution (note: XSLT 2.0 only). It works by
passing the tree through a set of "scrubbing" templates, and also
through a set of copying templates, repeating as necessary until both
results are the same. It assumes you don't have any whitespace-only
text nodes you want to preserve:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs"
version="2.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/|*|@*|text()" mode="copy scrub">
<xsl:copy>
<xsl:apply-templates select="*|@*|text()" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[empty(*|text()|@*[normalize-space()])]" mode="scrub"/>
<xsl:template match="@*[not(normalize-space())]" mode="scrub"/>
<xsl:template match="/">
<xsl:variable name="scrubbed">
<xsl:apply-templates select="." mode="scrub"/>
</xsl:variable>
<xsl:variable name="copied">
<xsl:apply-templates select="." mode="copy"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="deep-equal($scrubbed, $copied)">
<xsl:sequence select="$scrubbed"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="$scrubbed"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Tested only lightly....
Cheers,
Wendell
At 02:40 AM 12/3/2009, you wrote:
The problem with this is that only elements OR attributes are
stripped but not both at the same time.
Assume the following XML source:
<ns11:elem1 myattr="">
<ns22:subelem2 />
<ns22:subelem3></ns22:subelem3>
</ns11:elem1>
Then applying the XSLT script below will result in
<ns11:elem1>
</ns11:elem1>
As you can see the ns11:elem1 persists.
It is handled only in the remove attribute template and does not
match the other remove-empty-element template.
So how can I iteratively/recursively re-apply the script/templates
on the result again?
XSLT script:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="@*[normalize-space(.)='']"/>
<xsl:template match="*[not(node())]"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
On Wed, 2 Dec 2009 20:58:11 -0500, Syd Bauman wrote:
>How about matching the empty attributes and not generating any
>output?
> <xsl:template match="@*[normalize-space(.)='']"/>
>> How can I delete empty attributes as well?
======================================================================
Wendell Piez
mailto:wapiez(_at_)mulberrytech(_dot_)com
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
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--