Subject: Re: Can't identify last ancestor node
From: "Sam D. Chuparkoff" <sdc@xxxxxxxxxx>
Date: Tue, 28 Jun 2005 05:48:16 -0700
|
On Tue, 2005-06-28 at 01:36 -0700, Mat Bergman wrote:
> Using this XML data:
>
> <menudata>
> <menu name="link1"/>
> <menu name="link2">
> <menu name="link2a"/>
> <menu name="link2b"/>
> </menu>
> </menudata>
>
>
> I am producing this HTML output:
> <ul>
> <li>link1</li>
> <li>link2
> <ul>
> <li>link2a</li>
> <li>link2b</li>
> </ul>
> </li>
> </ul>
>
> I am using a convoluted stylesheet that tokenizes an
> attribute and generates the HTML output based on the
> attribute's value. My problem is identifying the last
> nested node, in this example "link2b", so that I can
> customize that node's output.
>
> My complete stylesheet is below, but to summarize I
> made two attempts:
>
> <xsl:for-each select="ancestor::menu">
> <xsl:if test="position()=last()">
> <xsl:text>Write custom end text here</xsl:text>
> </xsl:if>
> </xsl:for-each>
>
> and
>
> <xsl:if test="ancestor::menu[last()]">
> <xsl:text>Write custom end tag here</xsl:text>
> </xsl:if>
>
> Both attempts wrote to each individual node, not just
> the last one. How can I tell my stylesheet to write
> one thing for the last <menu> node, and something else
> for the rest?
Don't use xsl:text to write xml. Don't think in terms of generating
start and end tags. You can't separate the two. Forget about the ul s
for a bit, pull out your conditions, and make certain your creation of
li s looks something like:
<li><xsl:value-of select="@name"/></li>
and nothing like:
<xsl:text
disable-output-escaping="yes"><li></xsl:text>
<xsl:value-of select="@name"/>
<xsl:text
disable-output-escaping="yes"></li></xsl:text>
Then you can start asking: How do I get some ul s in there? (Hint: no
xsl:text allowed. Really.)
Though someone else will have to answer because I'll be offline.
sdc
> Here's the entire stylesheet:
>
> <?xml version="1.0"?>
> <xsl:stylesheet version="1.0"
>
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
>
> <xsl:output method="html" indent="yes"/>
>
> <!-- siteID determines if a link is displayed for a
> specific cobrand -->
> <xsl:param name="siteID" select="2"/>
>
> <!-- Displays navigation -->
> <xsl:template match="/">
>
> <ul>
>
> <!-- tokenize all <menu> nodes -->
> <xsl:for-each select="//menu">
>
> <!-- Tokenize attributes to check if siteID is
> excluded -->
> <xsl:call-template name="tokenize">
> <xsl:with-param name="string" select="@exsites"/>
> <xsl:with-param name="delimiters" select="','"/>
> <xsl:with-param name="level"
> select="'process-includeExclude'"/>
> </xsl:call-template>
>
> </xsl:for-each>
>
> </ul>
>
> </xsl:template>
>
>
> <!-- Extract individual values from comma-delimited
> attribute -->
> <xsl:template name="tokenize">
> <xsl:param name="string" select="''" />
> <xsl:param name="delimiters" select="' 	
'"
> />
> <xsl:param name="level" select="''" />
>
> <xsl:call-template name="_tokenize-delimiters">
> <xsl:with-param name="string" select="$string" />
> <xsl:with-param name="delimiters"
> select="$delimiters" />
> <xsl:with-param name="level" select="$level" />
> </xsl:call-template>
>
> </xsl:template>
>
>
> <xsl:template name="_tokenize-delimiters">
>
> <xsl:param name="string" />
> <xsl:param name="delimiters" />
>
> <xsl:param name="level" />
>
> <xsl:param name="last-delimit"/>
> <xsl:variable name="delimiter"
> select="substring($delimiters, 1, 1)" />
>
> <xsl:choose>
> <xsl:when test="not($delimiter)">
>
> <!-- Sends individual attribute value for processing
> -->
> <xsl:call-template name="process-includeExclude" >
> <xsl:with-param name="currentExsite"><xsl:value-of
> select="$string"/></xsl:with-param>
> </xsl:call-template>
>
> </xsl:when>
>
> <!-- process string until all tokens are separated
> -->
> <xsl:when test="contains($string, $delimiter)">
> <xsl:if test="not(starts-with($string,
> $delimiter))">
> <xsl:call-template name="_tokenize-delimiters">
> <xsl:with-param name="string"
> select="substring-before($string, $delimiter)" />
> <xsl:with-param name="delimiters"
> select="substring($delimiters, 2)" />
> <xsl:with-param name="level" select="$level" />
>
> </xsl:call-template>
> </xsl:if>
> <xsl:call-template name="_tokenize-delimiters">
> <xsl:with-param name="string"
> select="substring-after($string, $delimiter)" />
> <xsl:with-param name="delimiters"
> select="$delimiters" />
> <xsl:with-param name="level" select="$level" />
> </xsl:call-template>
> </xsl:when>
> <xsl:otherwise>
> <xsl:call-template name="_tokenize-delimiters">
> <xsl:with-param name="string" select="$string"
> />
> <xsl:with-param name="delimiters"
> select="substring($delimiters, 2)" />
> <xsl:with-param name="level" select="$level" />
> </xsl:call-template>
> </xsl:otherwise>
> </xsl:choose>
> </xsl:template>
>
>
> <xsl:template name="process-includeExclude"
> match="menu">
> <xsl:param name="currentExsite" select="''" />
>
> <!-- check if siteID is excluded or included -->
> <xsl:if test="$currentExsite!=$siteID">
> <xsl:if test="@incsites=$siteID or @incsites=0">
>
> <!-- Write <li> tags -->
> <xsl:text
> disable-output-escaping="yes"><li></xsl:text>
>
> <!-- Write list content -->
> <xsl:value-of select="@name"/>
>
> <!-- Nested list - Write nested <ul> tags -->
> <xsl:if test="count(menu) > 0">
> <xsl:text
> disable-output-escaping="yes"> <ul> </xsl:text>
> </xsl:if>
>
> <!-- Write </li> tags for top-level and nested items
> -->
> <xsl:if test="count(menu) = 0">
>
> <xsl:choose>
>
> <!-- This is where I am having trouble. I want this
> to appear only at the last menu/menu node. Instead
> it's selecting all menu ancestors. -->
>
> <!-- If it's the last sub-menu, close with an </li>
> and a </ul> -->
> <xsl:when test="ancestor::menu[last()]">
> <xsl:text
> disable-output-escaping="yes"></li></ul>
> </xsl:text>
> </xsl:when>
>
> <!-- If it's not the last sub-menu, close with an
> </li> -->
> <xsl:otherwise>
> <xsl:text
> disable-output-escaping="yes"></li>
> </xsl:text>
> </xsl:otherwise>
>
> </xsl:choose>
>
> </xsl:if>
>
> </xsl:if>
> </xsl:if>
>
>
> </xsl:template>
>
> </xsl:stylesheet>
>
>
> Thanks,
>
> -Mat
>
>
>
>
> __________________________________________________
> Do You Yahoo!?
> Tired of spam? Yahoo! Mail has the best spam protection around
> http://mail.yahoo.com
|