cascading deletion/copy in xsl

Discussion in 'XML' started by tschwartz@revasystems.com, Jan 4, 2007.

  1. Guest

    I have an xml document in which elements are hierarchically related to
    eachother conceptually. Unfortunately, the hierarchical relationship
    is not modelled in the schema (i.e., the elements are "flattened" in
    the document". I have a case in which I want to remove a high level
    element using xslt and want all the related lower-level elements to be
    removed as well. Is there an easy way to do this in a template?

    For example, imagine a relationship of elements describing animals
    starting with "animal" at the top of the hierarchy and ending in "pets"
    at the bottom:

    animal => class => beastie => breed => pet

    Given the xml below, say I wanted to remove the class named "Aves" and
    wanted to cause a cascading removal of all other elements related to
    "Aves". Is there a simple way to do this using xsl that helps me avoid
    writing specific templates for each child node of "animals"?

    <?xml version="1.0" encoding="utf-8"?>
    <animals>

    <classes>
    <class name="Mammalia"/>
    <class name="Aves"/>
    </classes>

    <beasties>
    <beast type="cat" class="Mammalia"/>
    <beast type="dog" class="Mammalia"/>
    <beast type="bird" class="Aves"/>
    </beasties>

    <breeds>
    <breed name="collie" type="dog"/>
    <breed name="beagle" type="dog"/>
    <breed name="persian" type="cat"/>
    <breed name="siamese" type="cat"/>
    <breed name="parakeet" type="bird"/>
    <breed name="crow" type="bird"/>
    </breeds>

    <pets>
    <pet name="rover" breed="collie"/>
    <pet name="fluffy" breed="persian"/>
    <pet name="tweety" breed="parakeet"/>
    </pets>

    </animals>

    The desired xml output would be this:

    <?xml version="1.0" encoding="utf-8"?>
    <animals>

    <classes>
    <class name="Mammalia"/>
    </classes>

    <beasties>
    <beast type="cat" class="Mammalia"/>
    <beast type="dog" class="Mammalia"/>
    </beasties>

    <breeds>
    <breed name="collie" type="dog"/>
    <breed name="beagle" type="dog"/>
    <breed name="persian" type="cat"/>
    <breed name="siamese" type="cat"/>
    </breeds>

    <pets>
    <pet name="rover" breed="collie"/>
    <pet name="fluffy" breed="persian"/>
    </pets>

    </animals>
    , Jan 4, 2007
    #1
    1. Advertising

  2. <> wrote in message
    news:...
    >I have an xml document in which elements are hierarchically related to
    > eachother conceptually. Unfortunately, the hierarchical relationship
    > is not modelled in the schema (i.e., the elements are "flattened" in
    > the document". I have a case in which I want to remove a high level
    > element using xslt and want all the related lower-level elements to be
    > removed as well. Is there an easy way to do this in a template?
    >
    > For example, imagine a relationship of elements describing animals
    > starting with "animal" at the top of the hierarchy and ending in "pets"
    > at the bottom:
    >
    > animal => class => beastie => breed => pet
    >
    > Given the xml below, say I wanted to remove the class named "Aves" and
    > wanted to cause a cascading removal of all other elements related to
    > "Aves". Is there a simple way to do this using xsl that helps me avoid
    > writing specific templates for each child node of "animals"?
    >
    > <?xml version="1.0" encoding="utf-8"?>
    > <animals>
    >
    > <classes>
    > <class name="Mammalia"/>
    > <class name="Aves"/>
    > </classes>
    >
    > <beasties>
    > <beast type="cat" class="Mammalia"/>
    > <beast type="dog" class="Mammalia"/>
    > <beast type="bird" class="Aves"/>
    > </beasties>
    >
    > <breeds>
    > <breed name="collie" type="dog"/>
    > <breed name="beagle" type="dog"/>
    > <breed name="persian" type="cat"/>
    > <breed name="siamese" type="cat"/>
    > <breed name="parakeet" type="bird"/>
    > <breed name="crow" type="bird"/>
    > </breeds>
    >
    > <pets>
    > <pet name="rover" breed="collie"/>
    > <pet name="fluffy" breed="persian"/>
    > <pet name="tweety" breed="parakeet"/>
    > </pets>
    >
    > </animals>
    >
    > The desired xml output would be this:
    >
    > <?xml version="1.0" encoding="utf-8"?>
    > <animals>
    >
    > <classes>
    > <class name="Mammalia"/>
    > </classes>
    >
    > <beasties>
    > <beast type="cat" class="Mammalia"/>
    > <beast type="dog" class="Mammalia"/>
    > </beasties>
    >
    > <breeds>
    > <breed name="collie" type="dog"/>
    > <breed name="beagle" type="dog"/>
    > <breed name="persian" type="cat"/>
    > <breed name="siamese" type="cat"/>
    > </breeds>
    >
    > <pets>
    > <pet name="rover" breed="collie"/>
    > <pet name="fluffy" breed="persian"/>
    > </pets>
    >
    > </animals>



    XSLT 1.0 solution (49 lines):

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:eek:utput omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="pClassToDel" select="'Aves'"/>

    <xsl:key name="kBeastByType" match="beast"
    use="@type"/>

    <xsl:key name="kBreedByName" match="breed"
    use="@name"/>

    <xsl:template match="node()|@*" name="identity">
    <xsl:copy>
    <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
    </xsl:template>

    <xsl:template match="class">
    <xsl:if test="not(@name = $pClassToDel)">
    <xsl:call-template name="identity"/>
    </xsl:if>
    </xsl:template>

    <xsl:template match="beast">
    <xsl:if test="not(@class = $pClassToDel)">
    <xsl:call-template name="identity"/>
    </xsl:if>
    </xsl:template>

    <xsl:template match="breed">
    <xsl:if test=
    "not(key('kBeastByType', @type)/@class = $pClassToDel)">
    <xsl:call-template name="identity"/>
    </xsl:if>
    </xsl:template>

    <xsl:template match="pet">
    <xsl:if test=
    "not(key('kBeastByType',
    key('kBreedByName', @breed)/@type
    )/@class
    =
    $pClassToDel)">
    <xsl:call-template name="identity"/>
    </xsl:if>
    </xsl:template>

    </xsl:stylesheet>

    Output:

    <animals>
    <classes>
    <class name="Mammalia" />
    </classes>
    <beasties>
    <beast type="cat" class="Mammalia" />
    <beast type="dog" class="Mammalia" />
    </beasties>
    <breeds>
    <breed name="collie" type="dog" />
    <breed name="beagle" type="dog" />
    <breed name="persian" type="cat" />
    <breed name="siamese" type="cat" />
    </breeds>
    <pets>
    <pet name="rover" breed="collie" />
    <pet name="fluffy" breed="persian" />
    </pets>
    </animals>

    XSLT 2.0 solution (40 lines):

    <xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    exclude-result-prefixes="xs"
    >

    <xsl:eek:utput omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="pClassToDel" select="'Aves'"/>

    <xsl:key name="kDeleted" match="beast"
    use="string(@class = $pClassToDel)"/>

    <xsl:key name="kDeleted" match="class"
    use="string(@name = $pClassToDel)"/>

    <xsl:key name="kDeleted" match="breed"
    use="string(key('kBeastByType',@type)/@class = $pClassToDel)"/>

    <xsl:key name="kDeleted" match="pet"
    use="string(key('kBeastByType',
    key('kBreedByName',@breed)/@type
    )
    /@class
    =
    $pClassToDel)"/>

    <xsl:key name="kBeastByType" match="beast"
    use="@type"/>

    <xsl:key name="kBreedByName" match="breed"
    use="@name"/>

    <xsl:template match="node()|@*" name="identity">
    <xsl:copy>
    <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
    </xsl:template>

    <xsl:template match="*[. intersect key('kDeleted', 'true')]"/>
    </xsl:stylesheet>

    Output:
    <animals>
    <classes>
    <class name="Mammalia"/>
    </classes>
    <beasties>
    <beast type="cat" class="Mammalia"/>
    <beast type="dog" class="Mammalia"/>
    </beasties>
    <breeds>
    <breed name="collie" type="dog"/>
    <breed name="beagle" type="dog"/>
    <breed name="persian" type="cat"/>
    <breed name="siamese" type="cat"/>
    </breeds>
    <pets>
    <pet name="rover" breed="collie"/>
    <pet name="fluffy" breed="persian"/>
    </pets>
    </animals>

    Hope this helped.

    Cheers,
    Dimitre Novatchev
    Dimitre Novatchev, Jan 5, 2007
    #2
    1. Advertising

  3. Guest

    Wonderful! Thank you very much!
    , Jan 5, 2007
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?SGFyYWxk?=

    Persistent cache contents after deletion

    =?Utf-8?B?SGFyYWxk?=, Feb 19, 2004, in forum: ASP .Net
    Replies:
    0
    Views:
    283
    =?Utf-8?B?SGFyYWxk?=
    Feb 19, 2004
  2. alanb

    FilePicker Deletion Access Denied

    alanb, Apr 26, 2004, in forum: ASP .Net
    Replies:
    0
    Views:
    368
    alanb
    Apr 26, 2004
  3. Replies:
    1
    Views:
    3,583
    A. Bolmarcich
    May 27, 2005
  4. Alex
    Replies:
    2
    Views:
    1,200
  5. Replies:
    26
    Views:
    2,083
    Roland Pibinger
    Sep 1, 2006
Loading...

Share This Page