RE: [xsl] Filter out elements that have one specific sub-element and nothing else

Subject: RE: [xsl] Filter out elements that have one specific sub-element and nothing else
From: stephan@xxxxxxxxxx
Date: Thu, 22 Feb 2007 10:01:43 +0800
Thx so much to all who replied.
I created a test sheet that tried all suggested methods, all seem to work. 

The big question now: which one would be the most efficient (fastest) one?

Here is the sheet for reference:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; 
version="1.0">

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">
        <bigresult>
            <take1>
                <xsl:comment>match="listitem [formatinfo [ not (sibling::* 
| 
                    sibling::text()[normalize-space()]) ]]"</xsl:comment>
                <xsl:apply-templates/>
            </take1>
            <take2>
                <xsl:comment>match="listitem[formatinfo and
                    not(*[not(self::formatinfo)]) and (normalize-space() = 
'')]"</xsl:comment>
                <xsl:apply-templates mode="take2"/>
            </take2>
            <take3>
                <xsl:comment>match="listitem[formatinfo][count(child::*) = 
1]"</xsl:comment>
                <xsl:apply-templates mode="take3"/>
            </take3>
            <take4>
 
<xsl:comment>select="listitem[node()[last()=1][self::formatinfo]]"</xsl:comment>
                <xsl:apply-templates mode="take4"/>
            </take4>
        </bigresult>

    </xsl:template>
    <!-- Clearing out the unwanted elementes one by one -->
    <!-- take 1-->
    <xsl:template match="listitem [formatinfo [ not (following-sibling::* 
| following-sibling::text()[normalize-space()]) ]]" />

    <!-- take 2-->
    <xsl:template mode="take2" match="listitem[formatinfo and 
not(*[not(self::formatinfo)]) and (normalize-space() = '')]" />
 
    <!-- take 3-->
    <xsl:template mode="take3" match="listitem[formatinfo][count(child::*) 
= 1]" />
 
    <!-- take 4-->
    <xsl:template mode="take4" 
match="llistitem[node()[last()=1][self::formatinfo]]" />
 
 
 
<!-- Standard copy templates for the rest-->
    <xsl:template match="node() | @*">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="node() | @*" mode="take2">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>
    </xsl:template>
 
    <xsl:template match="node() | @*" mode="take3">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="node() | @*" mode="take4">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>
    </xsl:template>
 
</xsl:stylesheet>

"Michael Kay" <mike@xxxxxxxxxxxx> wrote on 02/21/2007 09:28:43 PM:

> select="listitem[node()[last()=1][self::formatinfo]]"
> 
> Michael Kay
> 
> 
> > -----Original Message-----
> > From: stephan@xxxxxxxxxx [mailto:stephan@xxxxxxxxxx] 
> > Sent: 21 February 2007 13:05
> > To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> > Subject: [xsl] Filter out elements that have one specific 
> > sub-element and nothing else
> > 
> > Hi there,
> > 
> > I have an XML file like this:
> > 
> > <?xml version="1.0" encoding="UTF-8"?>
> > <funnylist>
> >     <listitem>
> >         <formatinfo color="yellow" />
> >         <stuffinside>Info</stuffinside> MoreInfo
> >     </listitem>
> >     <listitem>
> >         <formatinfo color="blue" />
> >     </listitem>
> >     <listitem>
> >         <formatinfo color="red" />EvenMoreInfo
> >     </listitem>
> > </funnylist>
> > 
> > I need to filter out this element:
> >     <listitem>
> >         <formatinfo color="blue" />
> >     </listitem>
> > 
> > The rule: if listitem contains only formatinfo and no other 
> > element or text then remove it.
> > 
> > I have no clue how to formulate the xPath.
> > Help appreciated.
> > :-) stw

Current Thread