Приглашаем посетить
Ларри (larri.lit-info.ru)

XSL and XSLT

Table of Contents
Previous Next

XSL and XSLT

XSL is the XML-based language for describing stylesheets. You've probably used Cascading Style Sheets (CSS) when working with static HTML. CSS is used to handle the presentation of an HTML document, and HTML is used for layout of the page. Within the XML world, XSL provides the instructions to an XSLT processor, describing how to handle XML data. So XSL performs a similar function to CSS.

An XSL document is well-formed XML and conforms with the XSL namespace. Although we've already looked at what makes an XML document well-formed, we haven't looked at namespaces. An XML namespace is a set of predefined elements. By creating a standardized list of elements, all XSLT processors will know, for example, that <xsl:comment></xsl:comment> will create a comment in the target document, like <!– –> in HTML. All you need to know is to include namespace declaration, xmlns:xsl="http://www.w3.org/1999/XSL/Transform", in the <xsl:stylesheet> element. You can find more information about namespaces online at: http://www.w3.org/TR/REC-xml-names/.

The different parts of XSL are described using the same naming conventions as XML: so within XSL the building blocks are called elements and attributes.

In this section of the chapter we will be using a tiny part of the XSL recommendation. XSL is a large subject and there are whole books written about it. We will be using enough XSL to render an XML document as an HTML table. For more information on XSL, see XSLT Programmer's Reference 2nd Edition from Wrox.

Sablotron

To use XSL with PHP you will need to use Sablotron. Sablotron, also known as Sablot, is a PHP extension that provides support for XSL, XSLT, and XPath, and is maintained by the Ginger Alliance (http://www.gingerall.com/). Sablotron requires the Expat parser to be already installed. If you've gotten this far through the chapter and have played with the SAX examples, then you've got Expat installed.

Installation and Verifying XSL

If Sablotron appeared in the phpinfo.php earlier, then it is already installed. If not, you can download the libraries from the Ginger Alliance (http://www.gingerall.com/).

UNIX Installation

After downloading the rpms take a look at the README file that is listed with the rpms. The installation instructions are in the README file. Install the rpm by typing:

    rpm -i sablotron-0.6x-x.i386.rpm

or

    rpm -i sablotron-devel-0.6x-x.i386.rpm

After installing Sablotron, you can re-compile PHP with the XSLT extension, add a –with-sablot string to your configuration string, re-compile, and install PHP. If you are having problems refer to the annotated manual on the PHP.net site: http://www.php.net/manual/en/ref.xslt.php.

Windows Installation

The download of PHP 4.0.6 should contain all the appropriate dlls to install Sablotron. They are in the PHP\dlls\ directory of the distribution.

To install Sablotron with PHP and Apache:

  • Stop Apache if it is running.

  • Extract the following dlls into the C:\Windows\System\ folder if you are running Windows98 or C:\WINNT\System32\ if you are running WindowsNT/2000:

    • expat.dll

    • sablot.dll

    • xmlparser.dll

    • xmltok.dll

  • Open your php.ini file and remove the comment from the line ;extension=php_sablot.dll. Save the php.ini file.

  • Restart Apache.

  • Run the code.

The Windows installer for IIS automatically places these files in their appropriate places.

XSL Example Code

For this example we need to have three files in the same directory:

  • travel.xml

  • travel.xsl

  • xslt_travel.php

The XML document, travel.xml, is the same file that we've been using throughout this chapter. travel.xsl is the file that contains the XSL stylesheet. travel.php is the file that has the PHP code that loads the XML and XSL files, calls the processor, and returns the result as HTML to the browser.

In the previous code examples the bulk of the work displaying the XML as an HTML table was done using PHP. In this example, the bulk of the work is done using XSL. Consequently, the XSL file is the largest of the three files used in this example.

travel.xsl is shown below. This file has two main sections, the head (or top-level) and the body of the document. In the head we define the version and namespace information for the file.

The body of the document starts with the <xsl:output> line. The structure of the body for this XSL consists of instructions to match parts of the XML document and descriptions of the formatting for that match. First we look for and match /Recordset. As Recordset is the root element, we can use it to identify the start of the XML file. As we want to have the contents of the XML file displayed as an HTML table, we use the Recordset element as an identifier of the start of the file. So we put the opening HTML in this section, like the <title>, <head>, and <body> tags:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

The following line creates a <meta> tag in the subsequent HTML file that looks like this: <meta http-equiv="Content-Type" content="text/html; charset=utf-8">:

    <xsl:output encoding="utf-8" method="html" indent="yes" />

As Recordset is the root element, we use it as the start of our HTML file:

      <xsl:template match="/Recordset">
        <html>
          <head>
            <title>XSL Travel</title>
          </head>
          <body>
            <h1>Travel Packages</h1>
            <table border="0">

We use an xsl:for-each statement to loop through both the instances of Travelpackage in the travel.xml file. Everything within the for-each loop is basically the same. We start a table row and populate it with the element name and value of that element.

The use of <xsl:text> isn't necessary in this code, but it is good practice to use it. The following samples in the XSL produce the same results on the screen:

Sample 1

Sample 2

Sample 3

<td>

Country_name

</td>

<td>

<xsl:text>Country_name</xsl:text
>

</td>

<td>

<xsl:text>

Country_name

</xsl:text>

<td>

However, Sample 3 produces different HTML. Sample 1 and Sample 2 produce HTML with no whitespace (one long line of HTML), whereas Sample 3 has whitespace in the form of a carriage return after the <td> and Country_name.

The next long block of code builds the table that displays the contents of the XML file. Using the for-each loop we cycle through each instance of Travelpackage. When the processor encounters the <xsl:value-of select"Elementname" /> element, it enters the value of the element. In this way the xsl:value-of element acts like a variable:

              <xsl:for-each select="Travelpackage">
                <tr>
                  <td>
                    <xsl:text>Country_name</xsl:text>
                  </td>
                  <td>
                    <xsl:value-of select="Country_name" />
                  </td>
                </tr>
                <tr>
                  <td>
                    <xsl:text>City</xsl:text>
                  </td>
                  <td>
                    <xsl:value-of select="City" />
                  </td>
                </tr>
                <tr>
                  <td>
                    <xsl:text>Resort</xsl:text>
                  </td>
                  <td>
                    <xsl:value-of select="Resort" />
                  </td>
                </tr>
              <tr>
                <td>
                  <xsl:text>Resort_rating</xsl:text>
                </td>
                <td>
                  <xsl:value-of select="Resort_rating" />
                </td>
              </tr>
              <tr>
                <td>
                  <xsl:text>Resort_typeofholiday</xsl:text>
                </td>
                <td>
                  <xsl:value-of select="Resort_watersports" />
                </td>
              </tr>
              <tr>
                <td>
                  <xsl:text>Resort_watersports</xsl:text>
                </td>
                <td>
                  <xsl:value-of select="Resort_watersports" />
                </td>
              </tr>
              <tr>
                <td>
                  <xsl:text>Resort_meals</xsl:text>
                </td>
                <td>
                  <xsl:value-of select="Resort_meals" />
                </td>
              </tr>
              <tr>
                <td>
                  <xsl:text>Resort_drinks</xsl:text>
                </td>
                <td>
                  <xsl:value-of select="Resort_drinks" />
                </td>
              </tr>
              <tr>
                <td>
                  <xsl:text>Package_dateofdep</xsl:text>
                </td>
                <td>
                  <xsl:value-of select="*/Package_dateofdep" />
                </td>
              </tr>
              <tr>
                <td>
                  <xsl:text>Package_price</xsl:text>
                </td>
                <td>
                  <xsl:value-of select="*/Package_price" />
                </td>
              </tr>
              <tr>
                <td colspan="2"><hr /></td>
              </tr>
            </xsl:for-each>
          </table>
        </body>
      </html>
    </xsl:template>
  </xsl:stylesheet>

Remember that in this chapter we are simply displaying the XML as an HTML file. We could use XSL to display almost anything that you can imagine. The XML file, travel.xml, is the same file that we're using throughout the chapter.

All we need to do with this code is to load the XSL and the XML files into a string and then invoke the XSLT processor. The XSLT processor returns (in this case) the formatted HTML to the browser as a string. All the work to format the XML is done by the processor when it follows the rules described in the XSL file. If you didn't want to reference an external file, then you can include the XSL string or XML string in the PHP code.

The following code (xslt_travel.php), shows reading the contents of the files into $xslData and $xmlData. As the variables $xslData and $xmlData are arrays, we need to convert them to strings, using the implode() function. Now that we've got strings, we can call the processor:

    <?php
    $xslData = file("travel.xsl", "r");
    $xmlData = file("travel.xml", "r");

    $xslStr = implode("", $xslData);
    $xmlStr = implode("", $xmlData);

    if (xslt_process($xslStr, $xmlStr, $result)) {
        echo($result);
    } else {
        echo("There is an error in the XSL transformation...\n");
        echo("\tError number: " . xslt_errno() . "\n");
        echo("\tError string: " . xslt_error() . "\n");
        exit;
    }
    ?>

Finally, to prove that the code does in fact work, here's what the resulting output looks like:

Click To expand

Table of Contents
Previous Next