Subject: Re: [xsl] Getting the deepest node and calculating relative paths From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx> Date: Fri, 26 Jan 2001 15:51:58 +0000 |
Linda wrote: > Where IS Jeni? How nice to be missed ;) Just a very busy couple of weeks, I'm afraid. One of the points of XSLTDoc was to provide an auto-documentation daemon ;) Anyway, to describe David C.'s typically verbose solution: David's using the translate() and string-length() functions in a very cunning way to count the number of '/' characters in a string. He does this by filtering out any of the *other* characters. The following variable is set up to hold any name characters in the paths you're using (i.e. everything aside from '/'). <xsl:variable name="l" select="'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@_'"/> Given one of Iresh's paths, e.g.: /Catalog/Department/Product/SKU Doing the following: translate('/Catalog/Department/Product/SKU', $l, '') will replace any of the characters held by the $l variable with nothing, i.e. turn the path to: '////' Then using the string-length() function on this will tell you the number of '/' characters in the path. Of course you have to know and specify *all* of the characters that might occur in a string to use this: if hyphens were used in the element names, for example, then you'd have to include them in the $l variable. Once you understand that, the rest is fairly straight forward. The main template locates the longest of the paths using the 'sort and select' method. The paths are sorted according to the number of '/' characters in them (identified through the translate() and string-length() functions as above), and the last of these is selected (they're sorted in ascending order, so the last is the longest). <xsl:template match="Root"> <Root> <xsl:for-each select="Paths/Path/@value"> <xsl:sort select="string-length(translate(.,$l,''))" data-type="number"/> <xsl:if test="position()=last()"> <LongestPath> <xsl:value-of select="."/> </LongestPath> ... </xsl:if> </xsl:for-each> </Root> </xsl:template> Constructing the relative paths involves cycling through each of the paths in turn using an xsl:for-each. First, though, the longest path is stored as $y and the number of steps in the longest path is stored as $x. <RelPaths> <xsl:variable name="y" select="."/> <xsl:variable name="x" select="string-length(translate(.,$l,''))"/> <xsl:for-each select="/Root/Paths/Path"> <RelPath> <xsl:attribute name="value"> ... </xsl:attribute> </RelPath> </xsl:for-each> </RelPaths> During the iterations, if the path is the same as the longest path, then only the '.' is required. If it's one of the other paths, you need a number of '../' steps (provided through the 'r' template) and the name element/attribute that's finally selected by the path (provided through the 'l' template). <xsl:choose> <xsl:when test="@value=$y">.</xsl:when> <xsl:otherwise> <xsl:call-template name="r"> <xsl:with-param name="x" select="$x - string-length(translate(@value,$l,''))"/> </xsl:call-template> <xsl:call-template name="l"/> </xsl:otherwise> </xsl:choose> The 'r' template repeats '../' a number of times, dependent on the $x parameter that's passed into it. It does this by recursion: as long as $x is more than 0 then it calls itself with $x being one less: <xsl:template name="r"> <xsl:param name="x" /> <xsl:if test="$x >= 0">../<xsl:call-template name="r"> <xsl:with-param name="x" select="$x -1"/> </xsl:call-template> </xsl:if> </xsl:template> The 'l' template steps through the path to find the final element/attribute through recursion. While the path contains a '/', it selects the string after the '/'. <xsl:template name="l"> <xsl:param name="s" select="@value"/> <xsl:choose> <xsl:when test="contains($s,'/')"> <xsl:call-template name="l"> <xsl:with-param name="s" select="substring-after($s,'/')"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$s"/> </xsl:otherwise> </xsl:choose> </xsl:template> I hope that helps, Jeni --- Jeni Tennison http://www.jenitennison.com/ XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
RE: [xsl] Getting the deepest node , Linda van den Brink | Thread | Re: [xsl] Getting the deepest node , David Carlisle |
RE: [xsl] xsl:variable containing x, Michael Kay | Date | Re: [xsl] document( ), Jeni Tennison |
Month |