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. Advertisements

  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. Advertisements

  3. Guest

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

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. Kevin Flood
    Replies:
    0
    Views:
    1,262
    Kevin Flood
    Sep 8, 2004
  2. Kevin Flood
    Replies:
    1
    Views:
    3,213
    Kevin Flood
    Sep 13, 2004
  3. Klaus Friese
    Replies:
    0
    Views:
    647
    Klaus Friese
    Nov 22, 2004
  4. Ray Tayek
    Replies:
    3
    Views:
    769
    Ray Tayek
    Nov 30, 2003
  5. Thomas S.

    XSL: textarea with xsl code???

    Thomas S., Feb 5, 2004, in forum: XML
    Replies:
    1
    Views:
    2,152
    Markus Spath
    Feb 5, 2004
  6. Replies:
    1
    Views:
    3,928
    A. Bolmarcich
    May 27, 2005
  7. Alex
    Replies:
    2
    Views:
    1,620
  8. Replies:
    26
    Views:
    2,591
    Roland Pibinger
    Sep 1, 2006
Loading...