On Aug 19, 2008, at 9:18 PM, Quinn Taylor wrote:
Ken, thanks so much for taking the time to help out. Sure enough,
your solution works as advertised. :-)
One thing I'd like to simplify/optimize is the number of recursive
descents. It seems that your code recurses all the way down to the
base case and back up for each path element to correctly construct
the parent href. This is certainly not an O(n^3) algorithm, but it
seems like a triangular number (http://mathworld.wolfram.com/TriangularNumber.html
). For very long paths, this creates more work than necessary. Even
so, I'll take what works over what doesn't. :-)
- Quinn
Come to think of it, a smart implementation could avoid recursion
altogether and opt for a linear algorithm. The whole point is that
you need to know how many ../ to string together for each path
component. Note that this is always equal to the number of slashes
between a given component and the last component. Thus, counting
the / in a path (with a judicious use of contains() and substring-
after() at the very beginning, then decrementing for each path
element should give the correct count. Inside the <a> tags, a simple
loop up to the current count should create the correct number of ../
in the link. I'm going to give that a shot as soon as I get my
toddler to bed. ;-)
- Quinn
And, after reading the documentation more thoroughly, I realized there
aren't for loops on variables, since XSL is a functional
language. :-) Must've had that confused with <xsl:for-each> on XML
elements. Regardless, I think I came up with a more straightforward
solution that minimizes "yo-yo" recursion. Just thought I'd share. You
can also see it in action here (for now):
http://dysart.cs.byu.edu/svn/cs628/code/
Thanks for the help, hope this is of use to someone else.
- Quinn
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html" indent="yes"/>
<xsl:template match="*">
<xsl:call-template name="printLinkedPath">
<xsl:with-param
name="path">/path/to/resource</xsl:with-param>
</xsl:call-template>
</xsl:template>
<!-- Split path components at '/', add parent links for each
component. -->
<xsl:template name="printLinkedPath">
<xsl:param name="path"/>
<xsl:choose>
<xsl:when test="$path = '/'">
<root>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="printComponentOfPath">
<xsl:with-param name="path"
select="$path"/>
<xsl:with-param name="levels">
<xsl:call-template
name="occurences">
<xsl:with-param name="needle"
select="'/'"/>
<xsl:with-param name="haystack"
select="$path"/>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Print links for each component except the last, with " / " in
between. -->
<xsl:template name="printComponentOfPath">
<xsl:param name="path"/>
<xsl:param name="levels" select="0"/>
<xsl:variable name="tail" select="substring-after($path,'/')"/>
<xsl:choose>
<!-- If there is no text after a slash, this is the last component.
-->
<xsl:when test="not($tail)">
<xsl:text> / </xsl:text>
<xsl:value-of select="$path"/>
</xsl:when>
<!-- Otherwise, print a link for this component an
continue on. -->
<xsl:otherwise>
<xsl:variable name="parentPath">
<xsl:call-template name="parentPath">
<xsl:with-param name="levels"
select="$levels"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="head"
select="substring-before($path,'/')"/>
<xsl:choose>
<xsl:when test="$head">
<xsl:text> / </xsl:text>
<a href="{$parentPath}"><xsl:value-of
select="$head"/></a>
</xsl:when>
<xsl:otherwise>
<a href="{$parentPath}"><root></a>
<!-- Leading "/" -->
</xsl:otherwise>
</xsl:choose>
<!-- Recursive call to print next path component.
-->
<xsl:call-template name="printComponentOfPath">
<xsl:with-param name="path"
select="$tail"/>
<xsl:with-param name="levels" select="$levels -
1"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Find the number of occurrences of needle in haystack. -->
<xsl:template name="occurences">
<xsl:param name="needle"/>
<xsl:param name="haystack"/>
<xsl:param name="found" select="0"/>
<!-- Find the next needle; return the count so far if none exists.
-->
<xsl:choose>
<xsl:when test="contains($haystack,$needle)">
<xsl:call-template name="occurences">
<xsl:with-param name="needle"
select="$needle"/>
<xsl:with-param name="haystack" select="substring-after($haystack,
$needle)"/>
<xsl:with-param name="found" select="$found +
1"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$found"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Create a parent path with N occurrences of "../" -->
<xsl:template name="parentPath">
<xsl:param name="levels" select="0"/>
<xsl:if test="$levels > 0">
<xsl:call-template name="parentPath">
<xsl:with-param name="levels" select="$levels -
1"/>
</xsl:call-template>
<xsl:text>../</xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
--~------------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--