I have an XSL template that matches any element with a <var>
child:
<xsl:template match="*[var]">
<xsl:copy >
<xsl:attribute name="editable">
<xsl:for-each select="var[@attr]">
<xsl:value-of
select="concat(@attr,
substring(' ',
1 div (position()!=last())))"/>
</xsl:for-each>
</xsl:attribute>
<xsl:attribute name="constraints">
<xsl:for-each select="var[@ok]">
<xsl:value-of
select="concat(@attr,':',@ok,
substring(';',
1 div (position()!=last())))"/>
</xsl:for-each>
</xsl:attribute>
<!-- if this is an <a> then we have to put the stuff inside it inside it -->
<xsl:apply-templates select="@*" />
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
It concatenates the attr
s of the var elements into the editable
attribute of the parent; and the ok
s into constraint
s.
Then I have a template that matches any <field>
element:
<xsl:template match="field">
<span>
<xsl:attribute name="field">
<xsl:choose>
<xsl:when test="boolean(@name)">
<xsl:value-of select="./@name"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>true</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:apply-templates />
</span>
</xsl:template>
This simply converts it to <span field="name">
with a name the same of the field, if the field had one, or else 'true'.
Problem I'm having is, *[var]
matches a field if the field has a <var>
as a child. But what I want to happen is for the *[var]
to match first, and then field
to match as well, but afterwards.
Currently, with an input of
<field name="field1">
<var attr="class" ok="small,smaller" />
Text
</field>
I get
<field name="field1" editable="class" constraints="class:small,smaller">
Text
</field>
But I want
<span field="field1" editable="class" constraints="class:small,smaller">
Text
</span>
I found some answers on SO about doing two passes but I'm not sure whether it's the right answer, nor quite how to implement the answers I did find. How should I approach this, and if there's an easy answer, what is it? :)
TIA Altreus
If you want to apply two templates to the same node, you can use xsl:next-match: from the highest-priority rule that matches a node, you can call xs:next-match to invoke the next-highest, and so on. You can adjust the priorities "by hand", of course, using the priority attribute on xsl:template.
There are several other possibilities here:
(a) it seems to me from a quick glance that the processing of the "var" element could be done in a template that matches the var element rather than *[var], in which case it can be invoked by xsl:apply-templates in the usual way
(b) the first template can invoke the second using apply-templates in a special mode
(c) the first template can construct a temporary element in a variable and then apply-templates to that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With