Back To Top

XSLT: SQL DDL aus XML erzeugen


SQL DML aus XML erzeugen

Comelio-Blog XSLT SQL DDL aus XMLXML-Daten eigenen sich auch für die Speicherung von kommagetrennten Werten bzw. zeichengetrennten Werten. Allerdings hat XML den Vorteil, dass es zwar trotz der größeren Datei die einzelnen Felder sehr genau beschreibt und man auch diese Daten sehr viel leichter lesen kann als eine Aneinanderreihung von Kurztexten oder Zahlen. Auch hier lässt sich eine attribut- und elementorientierte Form unterscheiden. In beiden Fällen repräsentieren die Kindelemente des Wurzelelements die einzelnen Datenreihen. Bei der attributorientierten Form stellen die einzelnen Attribute die Felder der Reihe dar. Bei der elementorientierten Form sind es die Kindelemente dieser Elemente.

Die Umwandlung von diesen Daten in tatsächliche kommagetrennte Werte (siehe Abschnitt CSV-Werte) erfolgt später. Hier soll es zunächst darum gehen, aus solchen Textdateien, die quasi die neuen CSV-Dateien in XML-Form darstellen, passende SQL-Befehle zu generieren, die dann sofort zur Datenbank geschickt werden können. Gesucht wird also ein XSLT-Transformationsdokument, das die INSERT-Befehle für die einzelnen Datensätze hervorbringt.

Folgendes Dokument enthält die zu transformierenden Daten. Es handelt sich um einen Ausschnitt der TARIF-Tabelle.

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="821_02.xslt"?>
<Tarifliste>
  <Tarif Name="Frühstück" Preis="0,5" Nr="1" Typ="p"/>
  <Tarif Name="Mittagspause" Preis="1" Nr="2" Typ="p"/>
  <Tarif Name="Abendessen" Preis="1" Nr="3" Typ="p"/>
  <Tarif Name="Mondschein1" Preis="0,5" Nr="4" Typ="p"/>
...

Attributorientierte »CSV-Werte«

Man durchläuft in der Transformation die einzelnen Reihen (Kinder des Wurzelelements) und innerhalb dieser Elemente dann die einzelnen Attribute (oder natürliche Elemente in der elementorientierten Form). Für jede Reihe werden die INSERT INTO- und VALUES-Klauseln erzeugt, wobei dann die einzelnen Attributwerte ausgegeben werden. Zur Sicherheit gibt man auch noch die einzelnen Spalten in der optionalen Spaltenliste an.

Erweiterungen dieser Datei könnte man darin sehen, dass für unterschiedliche Datenbanksysteme noch Variationen des SQL-Befehls zulässig oder über einen globalen Parameter auswählbar sind. Für MySQL könnte man z.B. mehrere INSERT-Befehle so aneinander hängen, dass nur die VALUES-Klauseln durch Komma getrennt mehrfach nacheinander auftreten. Dies verringert die Dateigröße. Zusätzlich ließe sich auch verhindern, die Spaltenliste auszugeben. Sie ist optional und wird nur dann benötigt, wenn eine Untermenge der in der Tabelle zur Verfügung stehenden Spalten und/oder eine andere Spaltenreihenfolge benutzt wird. Allerdings vergrößert die ständige Wiederholung der Spaltennamen natürlich die Dateigröße, sodass man sich hier überlegen könnte, sie tatsächlich entfallen zu lassen.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" version="1.0"
       encoding="ISO-8859-1" indent="yes"/>
  <xsl:template match="/">
    <!--Datenausgabe -->
    <xsl:for-each select="/*/*">
      <xsl:text>INSERT INTO </xsl:text>
      <xsl:value-of select="local-name(/*)"/>
      <!--Spaltenliste -->
      <xsl:text> (</xsl:text>
      <xsl:for-each select="/*/*[1]/@*">
        <xsl:value-of select="local-name(.)"/>
        <!--Trenner -->
        <xsl:if test="not(position()=last())">
          <xsl:text>, </xsl:text>
        </xsl:if>
      </xsl:for-each>
      <xsl:text>) 
</xsl:text>
      <xsl:text> VALUES (</xsl:text>
      <xsl:for-each select="@*">
        <xsl:text> '</xsl:text>
        <xsl:value-of select="."/>
        <xsl:text> ' </xsl:text>
        <!--Trenner -->
        <xsl:if test="not(position()=last())">
          <xsl:text>, </xsl:text>
        </xsl:if>
      </xsl:for-each>
      <xsl:text>); 
</xsl:text>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

Umwandlung der attributorientierten Form in SQL

Man erhält eine Auflistung von einzelnen INSERT-Befehlen für die angegebenen Spaltennamen und Werte.

INSERT INTO Tarifliste (Name, Preis, Nr, Typ) 
 VALUES ( 'Frühstück ' ,  '0,5 ' ,  '1 ' ,  'p ' ); 
INSERT INTO Tarifliste (Name, Preis, Nr, Typ) 
 VALUES ( 'Mittagspause ' ,  '1 ' ,  '2 ' ,  'p ' ); 
INSERT INTO Tarifliste (Name, Preis, Nr, Typ) 
 VALUES ( 'Abendessen ' ,  '1 ' ,  '3 ' ,  'p ' );

Ausgabe in SQL

Die Verarbeitung der attributorientierten Form ist tatsächlich bis auf zwei winzige Unterschiede völlig gleich. Es ließe sich auch überlegen, mit einem ODER-Ausdruck beide Varianten in einer Datei anzugeben. Wir drucken im nachfolgenden Quelltext nur einen Ausschnitt der Lösung für die attributorientierte Form ab und formatieren die geänderten Stellen fett.