xsl-list
[Top] [All Lists]

RE: Can't identify last ancestor node

2005-06-28 09:23:36
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(_at_)yahoo(_dot_)com] 
Sent: 28 June 2005 17:20
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
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(_at_)saxonica(_dot_)com> 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(_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" />

=== message truncated ===


__________________________________________________
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>
--~--