<product id="456">
<product id="457" defective="yes">
<product id="458">
<product id="459">
<product id="460" defective="yes">
When the context node is product 460, I need to iterate through it and preceding-siblings back to (but not including) the last defective one. That is, I need a for-each on products 458, 459, and 460, but not 457 or before.
It can't be assumed that I got to the context node be iterating through all products in order.
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kPreceding" match="product" use=
"generate-id(
(self::product|following-sibling::product)
[@defective='yes'][1]
)"/>
<xsl:template match="product[last()]">
<xsl:copy-of select="key('kPreceding', generate-id())"/>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML (corrected to be well-formed !!!):
<t>
<product id="456"/>
<product id="457" defective="yes"/>
<product id="458"/>
<product id="459"/>
<product id="460" defective="yes"/>
</t>
produces the wanted, correct result:
<product id="458"/>
<product id="459"/>
<product id="460" defective="yes"/>
Explanation:
Using a key for indexing any product by the generate-id()
of the first following-sibling product
that is defective (or self, if this product
is defective itself).