Frames erzeugen

(Auszug aus "XSLT Kochbuch" von Sal Mangano)

Problem

Sie möchten HTML generieren, dessen Inhalt mit HTML-Frames strukturiert ist.

Lösung

Wie im Rezept Verlinkte Dokumente erstellen werden Sie Modi einsetzen, um mehrere Durchgänge über das XML zu machen. Zuerst erzeugen Sie das Frameset-Containerdokument. Dazu verwenden Sie zwei Frames. Das kleinere linke Frame enthält die Namen der Verkäufer als Hyperlinks zur Aktivierung von Inhalten im Haupt-Frame. Das Haupt-Frame enthält die Verkaufszahlen des Verkäufers, den der Benutzer ausgewählt hat. Dieses Beispiel enthält standardmäßig ein Haupt-Frame, das angezeigt wird, sobald die Seite erstmals abgerufen wird:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html"/>
  <xsl:param name="URL"/>
  <xsl:template match="/">
    <xsl:apply-templates select="*" mode="frameset"/>
    <xsl:apply-templates select="*" mode="salespeople_frame"/>
    <xsl:apply-templates select="*" mode="sales_frames"/>
  </xsl:template>
  <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = -->
  <!--              Erzeuge Frameset-Container (mode ="frameset")                -->
  <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = -->
  <xsl:template match="salesBySalesperson" mode="frameset">
    <!-- Nicht standardkonformes Saxon-xsl:document! -->
    <xsl:document href="index.html">
      <html>
        <head>
          <title>Salesperson Frameset</title>
        </head>
        <frameset rows="100%" cols="25%, 75%" border="0">
          <frame name="salespeople" src="salespeople_frame.html" noresize=""/>
          <frame name="mainFrame" src="default_sales.html" noresize=""/>
        </frameset>
        <body bgcolor="#FFFFFF" text="#000000"></body>
      </html>
    </xsl:document>
  </xsl:template>
  <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = -->
  <!-- Erzeuge salespeople_frame.html  (mode = "salespeople_frame")              -->
  <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = -->
  <xsl:template match="salesBySalesperson" mode="salespeople_frame">
    <!-- Nicht standardkonformes Saxon-xsl:document! -->
    <xsl:document href="salespeople_frame.html">
      <html>
        <head>
          <title>Salespeople</title>
        </head>
        <body bgcolor="#FFFFFF" text="#000000">
          <table>
            <tbody>
              <xsl:apply-templates mode="index"/>
            </tbody>
          </table>
        </body>
      </html>
    </xsl:document>
  </xsl:template>
  <xsl:template match="salesperson" mode="index">
    <tr>
      <td>
        <a href="{concat(@name,'.html')}" target="mainFrame">
          <xsl:value-of select="@name"/>
        </a>
      </td>
    </tr>
  </xsl:template>
  <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = -->
  <!--                  Erzeuge @name.html  (mode = "content")                   -->
  <!-- =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  =  = -->
  <xsl:template match="salesperson" mode="sales_frames">
    <xsl:document href="default_sales.html">
      <html>
        <head>
          <title>Default</title>
        </head>
        <body bgcolor="#FFFFFF" text="#000000">
          <h1><center>Sales By Salesperson</center></h1>
          <br/>
          Click on a salesperson on the left to load his or her sales figures.
        </body>
      </html>
    </xsl:document>
    <xsl:document href="{concat(@name,'.html')}">
      <html>
        <head>
          <title><xsl:value-of select="@name"/></title>
        </head>
        <body bgcolor="#FFFFFF" text="#000000">
          <h1><center>Sales By Salesperson</center></h1>
          <h2><xsl:value-of select="@name"/></h2>
          <table border="1" cellpadding="3">
            <tbody>
              <tr>
                <th>SKU</th>
                <th>Sales (in US $)</th>
              </tr>
              <xsl:apply-templates mode="content"/>
            </tbody>
          </table>
        </body>
      </html>
    </xsl:document>
  </xsl:template>
  <xsl:template match="product" mode="content">
    <tr>
      <td><xsl:value-of select="@sku"/></td>
      <td align="right"><xsl:value-of select="@totalSales"/></td>
    </tr>
  </xsl:template>
</xsl:stylesheet>

Diskussion

Frames sind nützlich, um eine Seite in logische Abschnitte aufzuteilen. Allerdings gelten Frames mit sichtbaren oder in der Größe veränderbaren Rändern als ziemlich veraltet. Ihr Stylesheet kann für eine clientseitige Transformation nicht verwendet werden, weil es viele einzelne HTML-Dateien ausgibt, nämlich je eine für das Frameset, das linke Frame mit der Liste der Verkäufer sowie für jeden einzelnen Verkäufer.

Die Lösung demonstriert ein Beispiel, das dynamisch und nach oben hin offen ist, was die Anzahl der einzelnen Seiten angeht, die aus einer einzigen XML-Datei erzeugt werden können. Allerdings sind jene Fälle einfacher, in denen Frames mit clientseitiger XSLT-Verarbeitung verwendet werden können. Erzeugen Sie einfach eine Seite mit einem Frameset, in dem die Frames separate XML-Dokumente mit jeweils eigener Transformation enthalten:

<html>
  <head>
    <title>Frameset</title>
  </head>
  <frameset rows="100%" cols="25%, 75%" border="0">
    <frame name="leftFrame" src="left.xml" noresize="">
    <frame name="mainFrame" src="main.xml" noresize="">
  </frameset>
  <body bgcolor="#FFFFFF" text="#000000"></body>
</html>

Die verschiedenen XML-Dokumente müssen Sie deshalb für jedes Frame referenzieren, weil es nur eine xml-stylesheet-Verarbeitungsanweisung pro Datei geben darf. Aber Sie können den Inhalt trotzdem in einem Stylesheet aufbewahren, sofern Sie einen xinclude-Link verwenden, den Sie mit einem XSLT-Template verarbeiten.

left.xml sieht wie folgt aus:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="application/xml" href="left.xsl"?>
<xi:include href="salesBySalesperson.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>

main.xml ist ganz ähnlich:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="application/xml" href="main.xsl"?>
<xi:include href="salesBySalesperson.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>

left.xsl und main.xsl enthalten ein Template, das das xinclude-Element mit Hilfe der document-Funktion verarbeitet:

<!-- left.xsl -->
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html"/>
  <xsl:template match="xi:include" xmlns:xi="http://www.w3.org/2001/XInclude">
    <xsl:for-each select="document(@href,.)">
      <xsl:apply-templates/>
    </xsl:for-each>
  </xsl:template>
  <xsl:template match="salesBySalesperson">
    <html>
      <head>
        <title>Salespeople</title>
      </head>
      <body bgcolor="#FFFFFF" text="#000000">
        <table>
          <tbody>
            <xsl:apply-templates/>
          </tbody>
        </table>
      </body>
    </html>
  </xsl:template>
  <xsl:template match="salesperson">
    <tr>
      <td>
        <a href="{concat('main.xml#',@name)}" target="mainFrame">
        <xsl:value-of select="@name"/></a>
      </td>
    </tr>
  </xsl:template>
</xsl:stylesheet>

<!-- main.xsl -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html"/>
  <xsl:template match="xi:include" xmlns:xi="http://www.w3.org/2001/XInclude">
    <xsl:for-each select="document(@href)">
      <xsl:apply-templates/>
    </xsl:for-each>
  </xsl:template>
  <xsl:template match="salesBySalesperson">
    <html>
      <head>
        <title>Sales By Salesperson</title>
      </head>
      <body bgcolor="#FFFFFF" text="#000000">
        <xsl:apply-templates/>
      </body>
    </html>
  </xsl:template>
  <xsl:template match="salesperson">
    <h1><a name="{@name}"><center>Sales By Salesperson</center></a></h1>
    <h2><xsl:value-of select="@name"/></h2>
    <table border="1" cellpadding="3">
      <tbody>
        <tr>
          <th>SKU</th>
          <th>Sales (in US $)</th>
        </tr>
        <xsl:apply-templates />
      </tbody>
    </table>
    <div style="padding-top:1000"/>
  </xsl:template>
  <xsl:template match="product">
    <tr>
      <td><xsl:value-of select="@sku"/></td>
      <td align="right"><xsl:value-of select="@totalSales"/></td>
    </tr>
  </xsl:template>
</xsl:stylesheet>

In main.xsl, dem Haupt-Stylesheet, generieren Sie benannte Anker für alle Verkäufer und trennen diese großzügig mit Hilfe von viel Leerraum, indem Sie <div style="padding-top: 1000"/> verwenden. In left.xsl generieren Sie dann Links auf diese Anker. Diese Vorgehensweise simuliert in groben Zügen das Verhalten des Beispiels mit mehreren Seiten.

Siehe auch

Jeni Tennisons Buch XSLT and XPath on the Edge (M&T, 2001) enthält eine detaillierte Behandlung clientseitiger XSLT-Verarbeitung mit Frames, die zeigt, wie Sie mit JavaScript auch ausgefeiltere Ergebnisse erzielen können.

  

<< zurück vor >>

 

 

 

Tipp der data2type-Redaktion:
Zum Thema XSLT bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

Copyright © 2006 O'Reilly Verlag GmbH & Co. KG
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "XSLT Kochbuch" denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

O'Reilly Verlag GmbH & Co. KG, Balthasarstraße 81, 50670 Köln, kommentar(at)oreilly.de