I have a xsl:variable ($features-list) specified in my XSL which contains a tree fragment from an external XML file.
<xsl:variable name="features-list" select="document('features-list.xml', /)" />
This file contains a list of “feature” elements where each element’s value specifies a feature name. In the XML which I’m trying to transform (it’s actually a RNG schema) certain elements have attributes conveniently named “if-feature” which specify that a copy of such an element (or rather an entire subtree) should only appear in the transformed document if such an attribute is not present OR if the attribute appears but has a same value as one of the feature elements in the external file. This may potentially mean that entire subtrees may be omitted in the result document since the attribute is “inherited” from ancestors.
I’ve successfuly used this variable to fire or omit certain templates using checks like
<xsl:when test="not(@if-feature) or @if-feature and $features-list//*[.=current()/@if-feature]">
</xsl:when>
in any template. But this will only work when comparing the entries in the features list with the element which is currently being processed by the template. What I’d need now is something like this:
<xsl:apply-templates select="descendant::foo[ancestor-or-self::*[not(@if-feature) or $features-list//*[.=current()/@if-feature]]]"/>
where current() refers to the one of the ancestor-or-self elements. I’m actually trying to fire a template based on a condition like this: only process foo descendants of the current node of which ancestors (and itself) – if they have an if-feature attribute – it’s value must match one of the feature element values in $feature-list.
Can I express such a condition using XPath only? How?
Would an XSLT solution be more appropriate here? This would identify offending elements but doesn’t help me much because of XSLT limitations.
<xsl:for-each select="descendant::foo">
<xsl:for-each select="ancestor-or-self::*">
<xsl:choose>
<xsl:when test="@if-feature and not($features-list//*[.=current()/@if-feature])">
<!-- we have a hit, break and do not proceed - but wait, this is XSLT, not Java -->
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:for-each>
Trying my best to learn XSLT 1.0 here, so please refrain from providing solutions for 2.0.
What I’m trying to accomplish is to extract a valid RNG schema from an existing one which specifies feature based subtrees. I’ve actually done that already but it doesn’t work for ONE tiny smallish rarely-occuring case which is now driving me nuts. Through walls of fire. And bricks.
Edit: the specification of my condition was unclear, so I corrected it.
The XPath
=operator compares every node in a node set and yieldstrueif one of the nodes fulfills the comparison. So, just compare@if-featureto a set of nodes.General notes.
<xsl:for-each>. It does more harm than good, most of the time. Use<xsl:apply-templates>and<xsl:template>instead.For example, the alphabetically first
@if-feature:This is not exactly the same as a breakpoint, but it has the same effect.