You haven't told us what the context node is for your code snippets -
presumably it's the <menu> element that you're testing? In that case they
don't make any sense at all. Looking at the ancestors of a node can't tell
you whether it has any following siblings, for example. (From your question,
I think you may have confused your ancestors with your descendants).
Best way to do this is probably to set a global variable to the last menu
element:
<xsl:variable name="last-menu" select="(//menu)[last()]"/>
and then when processing each menu element, test
<xsl:if test=". is $last-menu"> (XSLT 2.0)
<xsl:if test="generate-id(.) = generate-id($last-menu)"/> (XSLT 1.0)
Michael Kay
http://www.saxonica.com/
-----Original Message-----
From: Mat Bergman [mailto:matbergman(_at_)yahoo(_dot_)com]
Sent: 28 June 2005 09:36
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Subject: [xsl] Can't identify last ancestor node
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?
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
--~------------------------------------------------------------------
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>
--~--
--~------------------------------------------------------------------
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>
--~--