Ein Formular ausfüllen

(Auszug aus "XSLT Kochbuch" von Sal Mangano)

Problem

Sie möchten XML-Daten in ein vordefiniertes Formular einfügen, bevor dieses an den Client übergeben wird.

Lösung

Sofern Sie XHTML benutzen oder anderweitig wohlgeformtes HTML erstellen, können Sie mit XSLT ein HTML-Dokument mit Daten aus einem XML-Dokument anreichern. An dieser Stelle werden wir Daten aus einem XML-Dokument in ein vorgefertigtes HTML-Formular einbauen. Stellen Sie sich z.B. vor, dass der Webdesigner Ihrer Firma ein Formular erstellt hat, das immer dann benutzt wird, wenn Online-Kunden einen Einkauf abschließen. Das Formular muss eine vom jeweiligen US-Bundesstaat des Kunden abhängige Verkaufssteuer enthalten. Diese Kunden geben ihren Bundesstaat an, wenn sie ihre Rechnungsadresse eingeben. Weil die Staaten, für die Ihre Firma Steuern eintreiben muss, sowie die Steuersätze selbst variabel sind, wäre es keine gute Idee, sie im Formular fest zu kodieren. Stattdessen könnte der Server die passenden Steuerdaten mit XSLT dynamisch ins Formular einsetzen.

Die Daten zur Verkaufssteuer könnten wie folgt gespeichert (oder aus einer Datenbank extrahiert worden) sein:

<salesTax>
  <state>
    <name>AL</name>
    <tax>4</tax>
  </state>
  <state>
    <name>AK</name>
    <tax>0</tax>
  </state>
  <state>
    <name>AZ</name>
    <tax>5.6</tax>
  </state>
  ...
  <state>
    <name>WY</name>
    <tax>4</tax>
  </state>
</salesTax>

Das vorgefertigte HTML-Formular könnte wie folgt aussehen:

<html>
  <head>
    <title>Check Out</title>
    <script type="text/javascript" language="JavaScript">
    <!--
    /* Initialisiere Steuersatz für vorgegebenen Bundesstaat */
    setTax(document.customerInfo.billState)
    /* Berechne Steuersatz neu, wenn Bundesstaat sich ändert */
    function setTax(field)
     {
    var value = new String(field.value)
    var commaPos = value.indexOf(",")
    var taxObj = document.customerInfo.tax
    var tax = value.substr(commaPos + 1)
    var subtotalObj = document.customerInfo.subtotal
    taxObj.value = tax
    document.customerInfo.total.value =
      parseFloat(subtotalObj.value) +
      (parseFloat(subtotalObj.value) * parseFloat(tax) / 100.00)
     }
    -->
    </script>
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <h1>Check Out</h1>
    <form name="customerInfo" method="post" action="">
      <table width="70%" border="0" cellspacing="3" cellpadding="3">
        <tr>
          <td width="7%">&#xa0;</td>
          <td width="32%">
            <div align="center"><b>Shipping Address</b></div>
          </td>
          <td width="20%">&#xa0;</td>
          <td width="7%">&#xa0;</td>
          <td width="34%">
            <div align="center"><b>Billing Address</b></div>
          </td>
        </tr>
        <tr>
          <td width="7%">Name</td>
          <td width="32%">
            <input type="text" name="shipName" maxlength="40" size="50" border="0" align="absmiddle"/>
          </td>
          <td width="20%">&#xa0;</td>
          <td width="7%">Name</td>
          <td width="34%">
            <input type="text" name="billName" maxlength="40" size="50" border="0" align="absmiddle"/>
          </td>
        </tr>
        <tr>
          <td width="7%">Address</td>
          <td width="32%">
            <input type="text" name="shipAddr" maxlength="40" size="50" border="0" align="absmiddle"/>
          </td>
          <td width="20%">&#xa0;</td>
          <td width="7%">Address</td>
          <td width="34%">
            <input type="text" name="billAddr" maxlength="40" size="50" border="0" align="absmiddle"/>
          </td>
        </tr>
        <tr>
          <td width="7%">City</td>
          <td width="32%">
            <input type="text" name="shipCity" maxlength="40" size="50" border="0" align="absmiddle"/>
          </td>
          <td width="20%">&#xa0;</td>
          <td width="7%">City</td>
          <td width="34%">
            <input type="text" name="billCity" maxlength="40" size="50" border="0" align="absmiddle"/>
          </td>
        </tr>
        <tr>
          <td width="7%">State</td>
          <td width="32%">
            <select name="shipState" size="1" align="absmiddle"></select>
          </td>
          <td width="20%">&#xa0;</td>
          <td width="7%">State</td>
          <td width="34%">
            <select name="billState" size="1" align="absmiddle" onChange="setTax(this)"></select>
          </td>
        </tr>
        <tr>
          <td width="7%">Zip</td>
          <td width="32%">
            <input type="text" name="shipZip" maxlength="10" size="15" border="0" align="absmiddle"/>
          </td>
          <td width="20%">&#xa0;</td>
          <td width="7%">Zip</td>
          <td width="34%">
            <input type="text" name="billZip" maxlength="10" size="15" border="0" align="absmiddle"/>
          </td>
        </tr>
        <tr>
          <td width="7%">&#xa0;</td>
          <td width="32%">&#xa0;</td>
          <td width="20%">&#xa0;</td>
          <td width="7%">&#xa0;</td>
          <td width="34%">&#xa0;</td>
        </tr>
        <tr>
          <td width="7%">&#xa0;</td>
          <td width="32%">&#xa0;</td>
          <td width="20%">&#xa0;</td>
          <td width="7%">Subtotal</td>
          <td width="34%">
            <input type="text" name="subtotal" readonly="1" value="100.00"/>
          </td>
        </tr>
        <tr>
          <td width="7%">&#xa0;</td>
          <td width="32%">&#xa0;</td>
          <td width="20%">&#xa0;</td>
          <td width="7%">Tax</td>
          <td width="34%">
            <input type="text" name="tax" readonly="1"/>
          </td>
        </tr>
        <tr>
          <td width="7%">&#xa0;</td>
          <td width="32%">&#xa0;</td>
          <td width="20%">&#xa0;</td>
          <td width="7%">Total</td>
          <td width="34%">
            <input type="text" name="total" readonly="1"/>
          </td>
        </tr>
      </table>
    </form>
  </body>
</html>

Die Transformation ist eine Vereinigung, bei der die Standardaufgabe darin besteht, die Inhalte aus dem vorgefertigten HTML in die Ausgabe zu kopieren (siehe das Rezept Probleme bei der Portierung von 1.0 zu 2.0 vermeiden). Sobald select-Elemente bei einem Bundesstaat vorgefunden werden, in den jeweils Ware und Rechnung geschickt werden, werden die Daten dieses Bundesstaates als option-Elemente eingefügt. Um dieses Beispiel etwas einfacher zu halten, habe ich den Namen des Staates sowie dessen Steuersatz in das value-Attribut des option-Elements aufgenommen, aber eventuell möchten Sie hierfür eine JavaScript-basierte Suche verwenden.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:import href="../util/copy.xslt"/>
  <xsl:output method="html"/>
  <xsl:template match="html">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="select[@name='shipState' or @name='billState']">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:for-each select="document('salesTax.xml')/salesTax/state">
        <option value="{name}',',{tax}">
          <xsl:value-of select="name"/>
        </option>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Diskussion

Bei dem Beispiel der hier behandelten Lösung kann es schon sein, dass es eindeutig besser geeignete Technologien als XSLT gibt (vielleicht denken Sie schon an ASP und JSP). Aber es gibt zwei Aspekte an diesem Beispiel, derentwegen Sie vielleicht doch eine XSLT-basierte Lösung vorziehen werden.

Erstens können Sie beobachten, dass der vorgegebene HTML-Code Standard-HTML enthält, d.h., es gibt keinerlei eingebautes Skript, weder server- noch clientseitig. Zwar wird doch ein bisschen clientseitiges Scripting verwendet, aber das könnte auch von der XSLT-Transformation eingefügt werden. Der Autor des vorgegebenen HTML-Codes braucht keinerlei Wissen über die verwendete Technologie oder Methode, mit der das Formular ausgefüllt wird, nachdem es vom Server geladen wurde. Tatsächlich werden vom Autor der Webseite überhaupt keine Programmierfähigkeiten verlangt. Umgekehrt benötigt der Programmierer der Transformation keinerlei Kenntnisse in HTML oder Grafikdesign. (Dieser Satz trifft ziemlich genau auf mich zu.)

Diese beiden müssen sich lediglich auf den Inhalt und bestimmte Namenskonventionen verständigen. Aus diesem Grund bietet eine transformationsbasierte Lösung bei dynamischen Inhalten eine wirkliche Trennung von Zuständigkeiten, die bei anderen Techniken fehlt.

Zweitens ermöglicht ein transformationsbasierter Ansatz weit mehr als das einfache Einfügen von Inhalt. Sie können damit auch vorhandene Inhalte entfernen und umordnen, ohne den HTML-Code mit fremdem Kauderwelsch zu verunstalten.

Siehe auch

Aus Zeit- und Platzgründen kann ich das Thema XForms in diesem Buch leider nicht behandeln, aber wenn Sie sich dafür interessieren, sollten Sie unbedingt einen genaueren Blick auf diese neue Technologie werfen. Das W3C beschreibt XForms wie folgt:

Das aktuelle Design von Webformularen sieht keine Trennung zwischen Zweck und Präsentation eines Formulars vor. XForms hingegen bestehen aus mehreren Abschnitten, die beschreiben, was das Formular macht und wie es aussieht. Dadurch ergeben sich flexiblere Möglichkeiten bei der Präsentation, auch von klassischen XHTML-Formularen, die an die Definition eines XML-Formulars angefügt werden könnten.

XForms verfolgt folgende Hauptziele:

  • Unterstützung von Browsern auf PDAs, Fernsehern und Desktop-Rechnern sowie von Druckern und Scannern
  • Reichhaltige Benutzeroberfläche für die Bedürfnisse von Anwendungen für geschäftliche und private Zwecke sowie für die Steuerung von Geräten
  • Entkoppelung von Daten, Logik und Präsentation
  • Verbesserte Internationalisierung
  • Unterstützung strukturierter Formulardaten
  • Fortgeschrittene Formularlogik
  • Mehrere Formulare pro Seite und mehrere Seiten pro Formular
  • Unterstützung von Unterbrechung und Wiederaufnahme beim Ausfüllen
  • Nahtlose Integration in andere Mengen von XML-Tags

  

<< 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