I’m developing an XSLT 1.0 stylesheet (and apply it using xsltproc). One of the templates in my script should perform some special handling for the first <sect1> element in a given parent node and some for the last <sect1> element. Right now this special handling is implemented like this:
<xsl:template match="sect1">
<xsl:if test="not(preceding-sibling::sect1)">
<!-- Special handling for first sect1 element goes here. -->
</xsl:if>
<!-- Common handling for all sect1 elements goes here. -->
<xsl:if test="not(following-sibling::sect1)">
<!-- Special handling for last sect1 element goes here. -->
</xsl:if>
</xsl:template>
I was wondering (just out of curiousity, the runtime speed of the script is fine for me): is there a more efficient way to do this? Is it likely that the XSLT processor will stop assembling the preceding-sibling::sect1 node-set after the first found match because it knows that it just needs to find one or zero elements?
I don’t know about xsltproc, but Saxon is very good at these sorts of optimizations. I believe it would only check for the first found match because it only needs to know whether the node-set is empty or not.
However you could always make sure by changing your tests as follows:
and
as this will only test for the first sibling along each axis. Note that the [1] in each case refers to the order of the XPath step, which is the order of the axis, not necessarily document order. So
preceding-sibling::sect1[1]refers to the sect1 sibling immediately preceding the current element, not the first sect1 sibling in document order. Because the direction of thepreceding-siblingaxis is reverse.