xsl:attribute-set is most often thought of for adding constant sets of XSL-FO properties, it’s easy to forget that, as it says in the XSLT 2.0 spec:
Evaluating the same attribute set more than once can produce different results, because although an attribute set does not have parameters, it may contain expressions or instructions whose value depends on the evaluation context.
This changing context was useful recently when customising an existing XSL-FO stylesheet included adding
id properties for use as the targets of
fo:basic-link cross-references. Since I couldn’t modify the base stylesheet, I was looking at having to replicate multiple templates just to add the
id properties where needed. However, to make it easy to customise the base stylesheet, its templates for the elements of interest each referred to named attribute sets and, more often than not, I was already adding to the same attribute sets in my stylesheet that imported the base stylesheet. It was simple, therefore, to add the
xsl:attribute for the
id property to the customisations of the attribute sets and be able to leave the base stylesheet’s templates unaltered.
The short form of what I was doing may be seen as:
<xsl:attribute-set name="fig"> <xsl:attribute name="id" select="generate-id()" /> </xsl:attribute-set>
where the changing context for each time the attribute set is used produces a different
id attribute each time, each containing the unique ID for the then-current context node.
However, the source XML had
id attributes on some elements already, and I wanted to hook into using the existing machinery in the base stylesheet for getting either the assigned ID or a generated ID, so the code in the customising stylesheet was more like:
<xsl:attribute-set name="fig"> <xsl:attribute name="id"> <xsl:call-template name="get-id" /> </xsl:attribute> </xsl:attribute-set> <xsl:template name="assign-id"> <xsl:param name="node" select="."/> <xsl:attribute name="id"> <xsl:call-template name="get-id"> <xsl:with-param name="node" select="$node"/> </xsl:call-template> </xsl:attribute> </xsl:template> <xsl:template name="get-id"> <xsl:param name="node" select="."/> <xsl:apply-templates select="$node" mode="id"/> </xsl:template>
assign-id template overrides the corresponding template in the base stylesheet and part of the function of the original
assign-id is broken out into
get-id for use in the attribute sets. And did I mention that the base stylesheet, and therefore also its customisation, was written in XSLT 1.0 for maximum portability?