RE: [xsl] Can't identify last ancestor node

Subject: RE: [xsl] Can't identify last ancestor node
From: "Michael Kay" <mike@xxxxxxxxxxxx>
Date: Tue, 28 Jun 2005 17:23:36 +0100
The two nodes you identify can be selected by

if (not(following-sibling::menu) and not(child::menu)) then ...

Michael Kay
http://www.saxonica.com/

  

> -----Original Message-----
> From: Mat Bergman [mailto:matbergman@xxxxxxxxx] 
> Sent: 28 June 2005 17:20
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject: RE: [xsl] Can't identify last ancestor node
> 
> This is close to what I need, but I need to be more
> clear. In this case, the context node is
> /menudata/menu/menu. I want to apply unique output for
> the last <menu> nodes in /menudata/menu/menu. For
> instance:
> 
> <menudata>
>      <menu name="link1">
>           <menu name="link1a"/>
>           <menu name="link1b"/>
>           <menu name="link1c"/>
>      </menu>
>      <menu name="link2">
>           <menu name="link2a"/>
>           <menu name="link2b"/>
>           <menu name="link2c"/>
>      </menu>     
> </menudata>
> 
> The <menu> nodes with name="link1c" and name="link2c"
> are the nodes that I'm after, but I can't figure out
> how to identify those nodes with XPath. 
> 
> Working with <xsl:variable name="last-menu"
> select="(//menu)[last()]"/> gives me the last <menu>
> node in the entire nodeset, so that my custom output
> is applied only to name="link2c". So maybe [last()] is
> not the predicate that I need.
> 
> Thanks for bearing with me,
> 
> -Mat
> 
> 
> 
> 
> 
> 
> 
> --- Michael Kay <mike@xxxxxxxxxxxx> wrote:
> 
> > 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@xxxxxxxxx] 
> > > Sent: 28 June 2005 09:36
> > > To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> > > 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" />
> > 
> === message truncated ===
> 
> 
> __________________________________________________
> Do You Yahoo!?
> Tired of spam?  Yahoo! Mail has the best spam protection around 
> http://mail.yahoo.com 

Current Thread