The CSS Class of XSLT: <xsl:attribute-set/>

During my vacation in Italy I have written as small MarkDown to PDF converter that we use for our letters and invoices here at Nelmio. For this purpose I have used FOP, Apache’s open source implementation of XSL-FO. I consider XSL-FO to be the easiest method to programmatically generate PDFs while remaining in total control of the produced result. Plus: it always gives me the opportunity to play with one of my fetish languages: XSLT.

While fiddling around my stylesheets I came across an XSLT element which I had never used before, the

1
<xsl:attribute-set/>

. It proved itself quite useful and I wish I would have known about it in my previous work with XSLT.

Definition and Usage

The

1
<xsl:attribute-set/>

is available in both versions of XSLT, namely 1.0 and 2.0. The W3C Recommendation of XSLT defines it as follows:

The xsl:attribute-set element defines a named attribute set: that is, a collection of attribute definitions that can be used repeatedly on different constructed elements.

The REQUIRED name attribute specifies the name of the attribute set. […] The content of the xsl:attribute-set element consists of zero or more xsl:attribute instructions […].

An

1
<xsl:attribute-set/>

looks as follows:

1
2
3
4
<xsl:attribute-set name="quote">
    <xsl:attribute name="padding-start">2.5cm</xsl:attribute>
    <xsl:attribute name="line-height">11pt</xsl:attribute>
</xsl:attribute-set>

Furthermore the the W3C Recommendation states:

Attribute sets are used by specifying a use-attribute-sets attribute on the xsl:element or xsl:copy instruction […].

Specifying a use-attribute-sets attribute is broadly equivalent to adding xsl:attribute instructions for each of the attributes in each of the named attribute sets to the beginning of the content of the instruction with the use-attribute-sets attribute […].

This means that the following two examples are equivalent:

1
2
3
4
5
6
7
8
9
10
11
12
13
<fo:block use-attribute-sets="quote">
    "We get our ethics from our history and judge our
     history by our ethics." - Ernst Troeltsch
</fo:block>

<!-- is equivalent to -->

<fo:block>
    <xsl:attribute name="padding-start">2.5cm</xsl:attribute>
    <xsl:attribute name="line-height">11pt</xsl:attribute>
    "We get our ethics from our history and judge our
     history by our ethics." - Ernst Troeltsch
</fo:block>

This is quite a useful element when working with XSL-FO lacks the concept of CSS classes.

Inheritance

The W3C Recommendation further states:

An attribute set may be defined in terms of other attribute sets by using the use-attribute-sets attribute on the xsl:attribute-set element itself.

This basically gives us inheritance.

We can now define a code

1
<xsl:attribute-set/>

that inherits the padding and line-height from the quote

1
<xsl:attribute-set/>

:

1
2
3
<xsl:attribute-set name="code" use-attribute-sets="quote">
    <xsl:attribute name="font-family">monospace</xsl:attribute>
</xsl:attribute-set>

Therefore the two following block definitions are equivalent:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<fo:block use-attribute-sets="code">
    var jQuery = function() {
        // ...
    }
</fo:block>

<!-- is equivalent to -->

<fo:block>
    <xsl:attribute name="padding-start">2.5cm</xsl:attribute>
    <xsl:attribute name="line-height">11pt</xsl:attribute>
    <xsl:attribute name="font-family">monospace</xsl:attribute>
    var jQuery = function() {
        // ...
    }
</fo:block>

Usage of multiple attribute sets

If we continue reading the W3C Recommendation, we find that a single element can have multiple attribute sets:

The value of the use-attribute-sets attribute is […] a whitespace-separated list of names of attribute sets.

Specifying a use-attribute-sets attribute is broadly equivalent to adding xsl:attribute instructions for each of the attributes in each of the named attribute sets to the beginning of the content of the instruction with the use-attribute-sets attribute, in the same order in which the names of the attribute sets are specified in the use-attribute-sets attribute.

We can now define a shout

1
<xsl:attribute-set/>

1
2
3
<xsl:attribute-set name="shout">
    <xsl:attribute name="text-transform">uppercase</xsl:attribute>
</xsl:attribute-set>

… and use it in conjunction with the quote

1
<xsl:attribute-set/>

:

1
2
3
<fo:block use-attribute-sets="quote shout">
    "I want a new Italian car!"
</fo:block >

Attribute sets compared to named templates

Everything we have seen here can be achieved with a named template as well. This is how I used to work it until now:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<xsl:template name="quote">
    <xsl:attribute name="padding-start">2.5cm</xsl:attribute>
    <xsl:attribute name="line-height">11pt</xsl:attribute>
</xsl:template>

<xsl:template name="code">
    <xsl:call-template name="quote"/>
    <xsl:attribute name="font-family">monospace</xsl:attribute>
</xsl:template>

<fo:block>
    <xsl:call-template name="code"/>
    var jQuery = function() {
        // ...
    }
</fo:block>

I personally think that the usage of an

1
<xsl:attribute-set/>

makes for much better readability. You immediately know that attributes are being added to your elements. With a named template you need to find the template and read the entire thing to be sure that it does not output anything. This being said, named templates offer more flexibility, as you can pass parameters into the templates.

July 11, 2011 by Pierre Spring in Development // Tags: , , , 7 Comments

7 Responses to The CSS Class of XSLT: <xsl:attribute-set/>

  1. cordoval says:

    is your MarkDown to PDF converter on github or can you share it? thanks!

  2. @cordoval: This will be subject to a future blog post… Including the source code ;)

  3. Kozuch says:

    Cant get the xsl:attribute tags inside fo:block tags get to work… using Apache FOP as processor…

  4. Kozuch says:

    use-attribute-sets seems to be wrong… xsl:use-attribute-sets works for me

  5. BopCatan says:

    Kozuch, you are rightif you’re working in the fo namespace then you need to make a call to the xsl namespace in order to use its attributes.

  6. Scott says:

    This is exactly what I needed. THANKS!