[xsl] Multiple level filtering with XSLT

Subject: [xsl] Multiple level filtering with XSLT
From: "Jeff Cann" <Jeff.Cann@xxxxxxxxxxxxxxx>
Date: Thu, 22 Jul 2004 16:29:15 +0100
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Please read the disclaimer at the bottom of this e-mail.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Hello,

I am developing a generic filtering stylesheet that needs to apply any number
of filters to an XML data source. The filters can be applied at any level of
the hierarchy.

On to the example... Say I have an XML file (see below) that I need to filter.
I want to filter out 'c' elements where '@x=1' and I also want to filter out
'd' elements where '@x>=7'. Problem is that when the 'd' elements are filtered
out, I am left with a 'c' element that contains no 'd' elements, this is not
allowed according to the XSD (must have at least 1 'c' in each 'd').

Please note:
* I have no access to modify the XSDs
* Filtering at any other step in the process (DB/xml source generation) is not
an option I have available.

To illustrate my example:
Start with the following XML file
<a x="1">
 <b x="1">
  <c x="1">
   <d x="1"/>
   <d x="2"/>
  </c>
  <c x="2">
   <d x="3"/>
   <d x="4"/>
   <d x="5"/>
  </c>
  <c x="3">
   <d x="6"/>
   <d x="7"/>
  </c>
  <c x="4">
   <d x="8"/>
   <d x="9"/>
  </c>
 </b>
</a>

After applying my XSL I end up with the following. Note the empty 'c' element.
I somehow need to exclude the 'c' elements that have had all their 'd'
elements filtered out.
<a x="1">
 <b x="1">
  <c x="2">
   <d x="3"/>
   <d x="4"/>
   <d x="5"/>
  </c>
  <c x="3">
   <d x="6"/>
  </c>
  <c x="4" />
 </b>
</a>

The XSL that I have currently (below) will work well if filtering occurs at
the same level, but will not work reliably when filtering occurs at multiple
levels.
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
version="1.0">
    <xsl:template match="*">
        <xsl:choose>
		<!-- first filter -->
            <xsl:when test="local-name()='c'">
                <xsl:if test="not(@x=1)">
                    <xsl:copy>
                        <xsl:copy-of select="@*"/>
                        <xsl:apply-templates/>
                    </xsl:copy>
                </xsl:if>
            </xsl:when>
		<!-- second filter -->
            <xsl:when test="local-name()='d'">
                <xsl:if test="not(@x&gt;=7)">
                    <xsl:copy>
                        <xsl:copy-of select="@*"/>
                        <xsl:apply-templates/>
                    </xsl:copy>
                </xsl:if>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy>
                    <xsl:copy-of select="@*"/>
                    <xsl:apply-templates/>
                </xsl:copy>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>


Any help or guidance would be greatly appreciated!

Thanks,
Jeff.


**********************************************************************
This email is intended for the named recipient(s) only. Its contents
are  confidential and may only be retained by the named recipient(s)
and may only be copied or  disclosed  with the consent of
LCH.Clearnet Limited.   If you are not an intended recipient please
delete this e-mail and notify postmaster@xxxxxxxxxxxxxxxx

The contents  of this  email are  subject to  contract in all cases,
and LCH.Clearnet Limited makes no contractual commitment save where
confirmed by hard copy.  LCH.Clearnet Limited accepts no liability,
including liability for negligence, in respect of any statement in
this email.

LCH.Clearnet Limited, Registered Office: Aldgate House,
33 Aldgate High Street, London EC3N 1EA.    Recognised as a Clearing
House under the Financial Services & Markets Act 2000. Reg in England No.25932
Telephone: +44 20 7426 7000              Internet: http://www.lchclearnet.com
**********************************************************************

Current Thread