xslt 1.0 I am afraid. I have access to exslt. I am otherwise looking to try to avoid using extension functions.
I need to find the most recently CLOSED xslt element of a particular type, rather than the most recently opened.
EDIT for clarity: ie if i moved a cursor backwards from current() through the text representation of the document until I hit </x>
then I wish to find the x that that is the closing tag of.
an illustrative example:
<e3>
<e2>
<x id="1">
<y/><!--if run with this 'y' as current() then it should pick up nothing-->
...
<x id="2">
<y/><!--if run with this 'y' as current() then it should pick up nothing-->
...
<x id="3"/>
<y/><!--if run with this 'y' as current() then it should pick up id="3"-->
</x>
...
<y/><!--if run with this 'y' as current() then it should pick up id="2"-->
</x>
</e2>
<e1>
...
<y/><!--if run with this 'y' as current() then it should pick up id="1"-->
</e1>
</e3>
[please note this is illustrative, the x's and y's can be arbitrarily nested withing containing elements]
All of my attempts to do this are nasty horror shows. The 'best' of them is simply to preprocess and put a self closing marker after each relevant close, and then use preceding::marker[1]/preceding-sibling:x[1]
but I hate doing a full copy to achieve this.
Otherwise my best bet is
<xsl:variable name="currentId" select="generate-id(.)"/>
preceding:x[1]/ancestor-or-self:x[following::node()[generate-id(.) = $currentId]][last()]
(ie find the most recently opened one, check its ancestors to see if the current node is after it)
The issue is efficiency, this potentially runs generate-id(.) though the whole document many, many times.
I guess I am asking if I am missing something 'obvious'.
TRYING AGAIN: Suppose I had the following xslt:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="intermediate">
<xsl:apply-template select="." mode="intermediate" />
</xsl:variable>
<xsl:copy>
<xsl:apply-templates mode="final" select="exslt:node-set($intermediate)"/>
</xsl:copy>
</xsl:template>
<xsl:template mode="intermediate" match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="intermediate" />
</xsl:copy>
</xsl:template>
<xsl:template mode="intermediate" match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="intermediate" />
</xsl:copy>
</xsl:template>
<xsl:template mode="intermediate" match="x">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="intermediate" />
</xsl:copy>
<heyAnXJustEndedHere/><!-- heyAnXJustEndedHere is guaranteed to not be an element name in the input-->
</xsl:template>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates mode="final" select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="y">
<xsl:copy>
<xsl:attribute name="lastClosingXhadID"><xsl:value-of select="preceeding::heyAnXJustEndedHere[1]/preceding-sibling::x[1]/@id"/></xsl:attribute>
<xsl:apply-templates mode="final" select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I am looking for a way to achieve the same output, for all input documents, without using node-set / 2 passes.
x[@id='3']
yet you expect different results.preceding-sibling::x[1]/@id
when evaluated from their respective contexts would return the values you expect.