Reputation: 435
In the sample XML there are two forms that match on number and type; in the second matching form I need to blank out the flag
element's value. I cannot change the level I am iterating over due to some interrelated stylesheets. I can do preceding-sibling
if I were iterating on formslist
but I can't seem to get the syntax correct when I am one level deeper on the flag
element. Both the number and type have to match before blanking it out.
<apply-templates match="formslist/flag">
<xsl:choose>
<xsl:when test=""></xsl:when>
</xsl:choose>
</apply-templates>
Sample XML
<forms>
<formslist>
<number>one</number>
<type>car</type>
<flag>da</flag>
</formslist>
<formslist>
<number>two</number>
<type>truck</type>
<flag>ex</flag>
</formslist>
<formslist>
<number>one</number>
<type>car</type>
<flag>da</flag>
</formslist>
</forms>
Upvotes: 0
Views: 313
Reputation: 243449
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="kFlag" match="formslist/flag"
use="concat(../number, '+', ../type)"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"flag/text()[generate-id(..)
!=
generate-id(key('kFlag',
concat(../../number,
'+',
../../type
)
)[1]
)
]
"/>
</xsl:stylesheet>
when applied on the provided XML document:
<forms>
<formslist>
<number>one</number>
<type>car</type>
<flag>da</flag>
</formslist>
<formslist>
<number>two</number>
<type>truck</type>
<flag>ex</flag>
</formslist>
<formslist>
<number>one</number>
<type>car</type>
<flag>da</flag>
</formslist>
</forms>
produces the wanted, correct result:
<forms>
<formslist>
<number>one</number>
<type>car</type>
<flag>da</flag>
</formslist>
<formslist>
<number>two</number>
<type>truck</type>
<flag>ex</flag>
</formslist>
<formslist>
<number>one</number>
<type>car</type>
<flag/>
</formslist>
</forms>
Do note the use of the Muenchian method for grouping, which is significantly faster than using comparison to preceding-sibling::*
(the last has a O(N^2)
-- quadratical performance).
Upvotes: 1
Reputation: 66723
When evaluated inside the template match for a flag
this should accomplish what you are looking for:
<xsl:variable name="thisFormslist" select=".." />
<flag>
<xsl:choose>
<xsl:when test="../preceding-sibling::*[$thisFormslist/number=number and $thisFormslist/type=type]">
<!--number and type have been seen before, so don't put a value for this flag-->
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</flag>
It creates a variable to reference the current formslist
element and then uses it in the predicate filter to compare the number
and type
to the preceding-sibling
elements of the parent element(formslist
).
Upvotes: 0