Altova Mailing List Archives>Archive Index >comp.text.xml Archive Home >Recent entries [Thread Prev] >Thread Next - Re: Recursively including all dependencies of an element Recursively including all dependencies of an elementTo: NULL Date: 6/4/2007 8:10:00 AM I found myself needing to find my way recursively through a document in XSLT, finding the dependencies one element had on others, and including only those in an initial set, their dependencies, the dependencies of those dependencies and so on. I managed to do it, but I'm not really happy with the method, and I'm wondering if anyone can suggest something better. My technique involves manipulating a string containing the names, calling a template that adds the names of the direct dependencies to a temporary string and then, if there are no additional names, returning that list, or, if there are additional ones, returning a recursive call to the template using the new list. It's pretty simple Recursion 101 code, but there's a level of indirection I don't like here. I shouldn't be using a string of names; I would rather be using node- sets. But whenever I tried that, I ran into issues of variables that held things that looked like but weren't really node-sets. Any suggestions for how I could do this without resorting to using the names, would be appreciated. Here's a simplified sample input document: <root> <x name="a"> <y dep="b"/> <y dep="c"/> </x> <x name="b"> <y dep="g"/> </x> <x name="c"> <y dep="a"/> </x> <x name="e"> <y dep="b"/> </x> <x name="f"> <y dep="c"/> <y dep="e"/> </x> <x name="g"> <y dep="h"/> </x> <x name="h"> <y dep="i"/> </x> <x name="i"/> <x name="j"> <y dep="i"/> </x> </root> Passed the parameter, "a, b", the stylesheet should note that 'a' depends on 'b' and' c', 'b' depends on 'g', which depends on 'h', which depends on 'i', which has no further dependencies. And 'c' depends on 'a'. That last is important because it demonstrates that this is not necessarily a tree structure. There are cycles. The output should be something like: <root> <x name="a"> <y dep="b"/> <y dep="c"/> </x> <x name="b"> <y dep="g"/> </x> <x name="c"> <y dep="a"/> </x> <x name="g"> <y dep="h"/> </x> <x name="h"> <y dep="i"/> </x> <x name="i"/> </root> The XSLT I use for this is pretty straightforward: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes" omit-xml-declaration="no" /> <xsl:param name="base" select="'a b'"/> <xsl:variable name="start"> <xsl:call-template name="normalize"> <xsl:with-param name="data" select="$base"/> </xsl:call-template> </xsl:variable> <xsl:template match="/"> <root> <xsl:variable name="names"> <xsl:call-template name="choose-names"> <xsl:with-param name="names" select="$start"/> </xsl:call-template> </xsl:variable> <xsl:for-each select="//x"> <xsl:if test="contains($names, @name)"> <xsl:text> </xsl:text><xsl:copy-of select="."/> </xsl:if> </xsl:for-each> </root> </xsl:template> <xsl:template name="normalize"> <xsl:param name="data" /> <xsl:value-of select="concat(normalize-space($data), ' ')" /> </xsl:template> <xsl:template name="choose-names"> <xsl:param name="names"/> <xsl:variable name="temp"> <xsl:for-each select="//x"> <xsl:variable name="name" select="@name"/> <xsl:if test="contains($names, $name) or //x[contains($names, @name)]/y[@dep = $name]"> <xsl:value-of select="@name"/><xsl:text> </ xsl:text> </xsl:if> </xsl:for-each> </xsl:variable> <xsl:choose> <xsl:when test="$names = $temp"> <xsl:value-of select="$temp"/> </xsl:when> <xsl:otherwise> <xsl:call-template name="choose-names"> <xsl:with-param name="names" select="$temp" /> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> I know there are holes in the string processing here. I'm sure I could tighten it up by using a separator other than space and then doing some escaping if the name contained the separator, but since I'd rather not be using the names anyway... So, does anyone have suggestions for how to do this without resorting to using strings (except to get the original set from the input parameter?) Thank you very much, -- Scott Sauyet | ||||||
| Company | Legal | Press | Partners | Careers | Sitemap | Contact Us | Altova Blog | Mobile | Full Site | |||
|
