Reputation: 17478
What I wish I could do in xsl is the following, but unfortunatly parent/position() is not valid.
XSL
<xsl:template match="li">
<bullet>
<xsl:apply-templates/>
</bullet>
<!-- if this is the last bullet AND there are no more "p" tags, output footer -->
<xsl:if test="count(ancestor::div/*) = parent/position()">
<footer/>
</xsl:if>
</xsl:template>
XML
<html>
<div>
<p>There is an x number of me</p>
<p>There is an x number of me</p>
<p>There is an x number of me</p>
<ul>
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
<li>list item</li>
</ul>
</div>
</html>
Anyone have any ideas how to figure out this problem from WITHIN my template match for li?
Thanks!
Upvotes: 1
Views: 11380
Reputation: 32094
Try this one:
<xsl:template match="li">
<bullet>
<xsl:apply-templates/>
</bullet>
<xsl:if test="position()=last() and not(../following-sibling::p)">
<footer/>
</xsl:if>
</xsl:template>
Upvotes: 1
Reputation: 6667
You can find the position of the parent node in the source tree by counting its preceding siblings:
<xsl:variable name="parent-position"
select="count(../preceding-sibling::*) + 1"/>
If you want to determine if there are any p
elements after the parent ul
element, you can test this without using positions at all:
<xsl:if test="../following-sibling:p">...</xsl:test>
However, as Dimitre and Oliver have noted, it is more in the spirit of XSLT to add the footer when processing the parent element. Also, the XPath expressions shown only care about order in the original source tree. If you intend to filter elements or reorder with xsl:sort
before processing, these paths will not work as desired, as they will look at the original ordering and include all nodes in the source tree.
Upvotes: 9
Reputation: 4262
If I understand correctly you are looking for the last li
; that is an li
with no li
elements following it. This can be tested as so:
<xsl:template match="li">
<bullet>
<xsl:apply-templates/>
</bullet>
<xsl:if test="not(following-sibling::li)">
<footer />
</xsl:if>
</xsl:template>
Although in the case you have given it seems to be more in the spirit of XSLT to add the footer when processing the end of the ul
:
<xsl:template match="ul">
<ul>
<xsl:apply-templates/>
</ul>
<footer />
</xsl:template>
<xsl:template match="li">
<bullet>
<xsl:apply-templates/>
</bullet>
</xsl:template>
Upvotes: 0
Reputation: 243449
A good way to do this in XSLT is:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="div">
<xsl:apply-templates/>
<footer/>
</xsl:template>
<xsl:template match="li">
<bullet>
<xsl:apply-templates/>
</bullet>
</xsl:template>
</xsl:stylesheet>
The inclusion of the <footer/>
is most natural at the end of the template that matches div
and there is no need to try to compare any positions.
Upvotes: 2