element-available() Function |
Determines if a given element is available to the XSLT processor. This function allows you to design stylesheets that react gracefully if a particular element is not available to process an XML document.
Inputs
The element's name. The name should be qualified with a namespace; if the namespace URI is the same as the XSLT namespace URI, then the element name refers to an element defined by XSLT. Otherwise, the name refers to an extension element. If the element name has a null namespace URI, then the element-available function returns false.
Output
The boolean value true if the element is available; false otherwise.
Defined in
XSLT section 15, Fallback.
Example
We'll use the following example to test the element-available() function:
    <?xml version="1.0"?>
    <book>
      <title>XSLT</title>
      <chapter>
        <title>Getting Started</title>
        <para>If this chapter had any text, it would appear here.</para>
      </chapter>
      <chapter>
        <title>The Hello World Example</title>
        <para>If this chapter had any text, it would appear here.</para>
      </chapter>
      <chapter>
        <title>XPath</title>
        <para>If this chapter had any text, it would appear here.</para>
      </chapter>
      <chapter>
        <title>Stylesheet Basics</title>
        <para>If this chapter had any text, it would appear here.</para>
      </chapter>
      <chapter>
        <title>Branching and Control Elements</title>
        <para>If this chapter had any text, it would appear here.</para>
      </chapter>
      <chapter>
        <title>Functions</title>
        <para>If this chapter had any text, it would appear here.</para>
      </chapter>
      <chapter>
        <title>Creating Links and Cross-References</title>
        <para>If this chapter had any text, it would appear here.</para>
      </chapter>
      <chapter>
        <title>Sorting and Grouping Elements</title>
        <para>If this chapter had any text, it would appear here.</para>
      </chapter>
      <chapter>
        <title>Combining XML Documents</title>
        <para>If this chapter had any text, it would appear here.</para>
      </chapter>
    </book>
Here is our stylesheet:
    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:redirect="org.apache.xalan.xslt.extensions.Redirect"

      xmlns:saxon="http://icl.com/saxon"
      extension-element-prefixes="redirect saxon">

      <xsl:output method="html"/>

      <xsl:template match="/">
        <xsl:choose>
          <xsl:when test="element-available('redirect:write')">
            <xsl:for-each select="/book/chapter">
              <redirect:write select="concat('chapter', position(), '.html')">
                <html>
                  <head>
                    <title><xsl:value-of select="title"/></title>
                  </head>
                  <body>
                    <h1><xsl:value-of select="title"/></h1>
                    <xsl:apply-templates select="para"/>
                    <xsl:if test="not(position()=1)">
                      <p>
                        <a href="chapter{position()-1}.html">Previous</a>
                      </p>
                    </xsl:if>
                    <xsl:if test="not(position()=last())">
                      <p>
                        <a href="chapter{position()+1}.html">Next</a>
                      </p>
                    </xsl:if>
                  </body>
                </html>
              </redirect:write>
            </xsl:for-each>
          </xsl:when>
          <xsl:when test="element-available('saxon:output')">
            <xsl:for-each select="/book/chapter">
              <saxon:output file="chapter{position()}.html">
                <html>
                  <head>
                    <title><xsl:value-of select="title"/></title>
                  </head>
                  <body>
                    <h1><xsl:value-of select="title"/></h1>
                    <xsl:apply-templates select="para"/>
                    <xsl:if test="not(position()=1)">
                      <p>
                        <a href="chapter{position()-1}.html">Previous</a>
                      </p>
                    </xsl:if>
                    <xsl:if test="not(position()=last())">

                      <p>
                        <a href="chapter{position()+1}.html">Next</a>
                      </p>
                    </xsl:if>
                  </body>
                </html>
              </saxon:output>
            </xsl:for-each>
          </xsl:when>
          <xsl:otherwise>
            <html>
              <head>
                <title><xsl:value-of select="/book/title"/></title>
              </head>
              <xsl:for-each select="/book/chapter">
                <h1><xsl:value-of select="title"/></h1>
                <xsl:apply-templates select="para"/>
              </xsl:for-each>
            </html>
          </xsl:otherwise>
        </xsl:choose>
        <xsl:if test="not(element-available('write'))">
          <xsl:message terminate="no">
            The <write> element is not available!
          </xsl:message>
        </xsl:if>
      </xsl:template>

      <xsl:template match="para">
        <p><xsl:apply-templates select="*|text()"/></p>
      </xsl:template>

    </xsl:stylesheet>
This stylesheet attempts to take the content in the XML file and write portions of it out to different HTML files. The first <chapter> element is written to the file chapter1.html, the second <chapter> element is written to the file chapter2.html, and so on. Our stylesheet attempts to use Xalan's <redirect:write> element first; if that element is not available, it checks for Saxon's <saxon:output> element. If neither of those elements is available, it writes the contents of all <chapter> elements to the same output stream. The stylesheet also calls the element-available() function with the nonqualified element name write; this call always returns false because the element name is not namespace qualified.

When we use Xalan to process the XML file with our stylesheet, here are the results on the console:

    file:///D:/O'Reilly/XSLT/bookSamples/AppendixC/elementavailable.xsl; Line 66;
    Column 35; The <write> element is not available!

The stylesheet generates the files chapter1.html through chapter9.html, with each file containing data from one of the <chapter> elements in the original file. Our stylesheet also generates hyperlinks between the chapter files; here's what chapter3.html looks like:

    <html>
       <head>
          <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

          <title>XPath</title>
       </head>
       <body>
          <h1>XPath</h1>
          <p>If this chapter had any text, it would appear here.</p>
          <p><a href="chapter2.html">Previous</a></p>
          <p><a href="chapter4.html">Next</a></p>
       </body>
    </html>

When rendered in a browser, the file looks like Figure C-1.

Sample HTML output file

Clicking on the Previous link takes you to the file chapter2.html, while clicking on the Next link takes you to chapter4.html.

Using our stylesheet with Saxon (using the command java com.icl.saxon.StyleSheet chapterlist.xml elementavailable.xsl) produces similar results on the console:

    The <write> element is not available!

Although the format of the message is slightly different, the output in the multiple HTML files is the same.

Finally, if we use the Oracle XML parser, none of the elements we query will be available, so all the output is written to a single file. We'll invoke the processor with this command. (The command should be on one line.)

    java oracle.xml.parser.v2.oraxsl chapterlist.xml
      elementavailable.xsl chapters.html

Here's the console output:

    Message: The <write> element is not available!

The output file, chapters.html, looks like this:

    <html xmlns:redirect="org.apache.xalan.xslt.extensions.Redirect"
      xmlns:saxon="http://icl.com/saxon">
       <head>
          <META http-equiv="Content-Type" content="text/html">
          <title>XSLT</title>
       </head>
       <h1>Getting Started</h1>
       <p>If this chapter had any text, it would appear here.</p>
       <h1>The Hello World Example</h1>
       <p>If this chapter had any text, it would appear here.</p>
       <h1>XPath</h1>
       <p>If this chapter had any text, it would appear here.</p>
       <h1>Stylesheet Basics</h1>
       <p>If this chapter had any text, it would appear here.</p>
       <h1>Branching and Control Elements</h1>
       <p>If this chapter had any text, it would appear here.</p>
       <h1>Functions</h1>
       <p>If this chapter had any text, it would appear here.</p>
       <h1>Creating Links and Cross-References</h1>
       <p>If this chapter had any text, it would appear here.</p>
       <h1>Sorting and Grouping Elements</h1>
       <p>If this chapter had any text, it would appear here.</p>
       <h1>Combining XML Documents</h1>
       <p>If this chapter had any text, it would appear here.</p>
    </html>

When rendered, our output looks like Figure C-2.

HTML document listing all chapters

In this example, the element-available() function allows us to determine what processing capabilities are available and respond gracefully to whatever we find.