Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

cascading deletion/copy in xsl

0 views
Skip to first unread message

tsch...@revasystems.com

unread,
Jan 4, 2007, 5:40:47 PM1/4/07
to
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>

Dimitre Novatchev

unread,
Jan 4, 2007, 7:56:44 PM1/4/07
to

<tsch...@revasystems.com> wrote in message
news:1167950447.0...@11g2000cwr.googlegroups.com...


XSLT 1.0 solution (49 lines):

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output 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:output 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


tsch...@revasystems.com

unread,
Jan 5, 2007, 2:36:56 PM1/5/07
to
Wonderful! Thank you very much!

0 new messages