Closest Ancestor Matching Condition
-
XSLT sometimes makes me think outside of my normal thought process. Assuming the order of nodes is not deterministic, I couldn't think of a simple way to get the first ancestor node (inclusive of the current node) matching a certain condition. "First", in this case, meaning the most deeply descended node. So, I decided to get the node from the set of ancestors for which there did not exist an ancestor in that same node set which matched the node.
<!-- Get ancestors and self. -->
<xsl:for-each select="$currentPage/ancestor-or-self::*/*[local-name() = $propertyName]/parent::*"><!-- Remember the ID of the current node. -->
<xsl:variable name="currentId" select="./@id" /><!-- Does the current node exist in the ancestors of the above result set? -->
<xsl:if test="count($currentPage/ancestor-or-self::*/*[local-name() = $propertyName]/parent::*/ancestor::*[@id=$currentId]) = 0"><!-- We've found the closest ancestor matching the condition. --> <xsl:value-of select="local-name(.)" />
</xsl:if>
</xsl:for-each>
If this were C#, I'd just use a while loop:
while(node != null && !node.HasProperty(propertyName))
{
node = node.Parent;
}I could have also created a recursive XSLT function to do something similar, but function calls in XSLT are so verbose that it wouldn't be worth it in this case. XSLT and LISP are two languages which always manage to get me really thinking (that could be seen as a good or a bad thing). :)