<xsl:attribute>

Sometimes we want to set attribute values in a generated XML document. For example we might want to set the background color red if a memo has a priority value of high:

<h1 style="background:red">Firewall problems</h1>

Regarding our memo example this may be achieved by:

<xsl:template match="/memo">
  <html>
   ...
    <body>
      <xsl:variable name="messageColor" ❶>
        <xsl:choose>
          <xsl:when test="@priority = 'low'">green</xsl:when>
          <xsl:when test="@priority = 'medium'">yellow</xsl:when>
          <xsl:when test="@priority = 'high'">red</xsl:when>
        </xsl:choose>
      </xsl:variable>
      <h1 style="background:{$messageColor};" ❷>
        <xsl:value-of select="subject"/>
      </h1>
    </body>
  </html>
</xsl:template>

Definition of a color name depending on the attribute priority's value. The set off possible attribute values (low,medium,high) is mapped to the color names (green, yellow,red).

The color variable is used to compose the attribute style's value. The curly {...} braces are part of the XSL standard's syntax. They are required here to instruct the XSL processor to substitute the local variable messageColor's value instead of simply copying the literal string $messageColor itself to the output document e.g. generating <h1 style = "background:$messageColor;">.

Instead of constructing an extra variable XSL offers a slightly more compact way for the same purpose. The <xsl:attribute> element allows us to define the name of an attribute to be added together with an attribute value specification:

<xsl:template match="/memo">
  <html>
   ...
      <h1>
        <xsl:attribute name="style">
          <xsl:text>background:</xsl:text>
          <xsl:choose>
            <xsl:when test="@priority = 'low'">green</xsl:when>
            <xsl:when test="@priority = 'medium'">yellow</xsl:when>
            <xsl:when test="@priority = 'high'">red</xsl:when>
          </xsl:choose>
        </xsl:attribute>
        <xsl:value-of select="subject"/>
      </h1>
    </body>
  </html>
</xsl:template>

exercise No. 56

Adding a table of contents (toc) Create comment in forum

Q:

For larger document instances it is convenient to add a table of contents to the generated Xhtml document.

For this exercise you need a unique string value for each <chapter> node. If a <chapter>'s id attribute had been declared as #REQUIRED its value would do this job perfectly. Unfortunately you cannot rely on its existence since it is declared to be #IMPLIED and may thus be absent.

XSL offers a standard function for this purpose namely generate-id(...). In a nutshell this function takes a XML node as an argument (or being called without arguments it uses the context node) and creates a string value being unique with respect to all other nodes in the document. For a given node the function may be called repeatedly and is guaranteed to always return the same value during the same transformation run. So it suffices to add something like <a href="#{generate-id(...)}"> or use it in conjunction with <xsl:attribute>.

A:

We use the generate-id() function to create a unique identity string for each chapter node. Since we also want to define links to the table of contents we need another unique string value. It is tempting to simply use a static value like __toc__ for this purpose. However we can not be sure that this value coincides with one of the generate-id() function return values.

A cleaner solution uses the <book> node's generated identity string for this purpose. As stated before this value is definitively unique:

<xsl:template match="/book">
...
    <body>
      <h1><xsl:value-of select="title"/></h1>
        <h2 id="{generate-id(.)}" ❶>Table of contents</h2>
        <ul>
        <xsl:for-each select="chapter">
          <li>
            <a href="#{generate-id(.)}" ❷><xsl:value-of select="title"/></a>
          </li>
        </xsl:for-each>
      </ul>
      <xsl:apply-templates select="chapter"/>
    </body>
  </html>
</xsl:template>

<xsl:template match="chapter">
  <h2 id="{generate-id(.)}" ❸>
    <a href="#{generate-id(/book)}" ❹>
      <xsl:value-of select="title"/>
    </a>
  </h2>
  <xsl:apply-templates select="para"/>
</xsl:template>
...

The current context node is <book>. We use it as argument to generate-id() to create a unique identity string.

The <xsl:for-each> iterates over all <chapter> nodes. We reference the corresponding target nodes being created in .

Each <chapter>'s heading is supplied with a unique identity string being referenced from .

Clicking on a chapter's title shall take us back to the table of contents (toc). So we create a hypertext link referencing our toc heading's identity string being defined in .