Most recent siblings back to some condition

2019-08-05 06:14发布

问题:

<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.

回答1:

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).



标签: xslt xpath