Der easydb XML-Importer ist ein Kommandozeilen-Tool zum Import von XML-Daten in relationale Datenbanken. Es gibt keine Verbindung und Relation zur easydb. Mit dem Kommandozeilen-Tool können ganz allgemein XML-Dateien in PostgreSQL-Datenbanken importiert werden.
Für einen Import müssen mindestens drei Dateien angelegt werden:
import_test.xml
)import_test.xsl
)import_easydb.xml
)1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: | <!-- datei: import_easydb_plan.xml --> <plan name="import_test" xmlns="http://schema.programmfabrik.de/imexporter-plan/0.1"> <build-steps> <step type="splitxml"> <split-level>1</split-level> <num-tuples>10000</num-tuples> </step> <step type="xslt"> <xsl-file>import_test.xsl</xsl-file> </step> <step type="databaseimport"> <description-file>import_easydb.xml</description-file> </step> </build-steps> </plan> |
Der Import-Plan wird mit dem folgenden Kommando ausgeführt:
/opt/easydb/server/bin/imexporter \
-d "host=... port=... dbname=... user=... password=..." \
-p import_easydb_plan.xml \
-i import_test.xml
Bitte beachten Sie, dass der imexporter aktuell nur UTF-8-kodierte Dateien unterstützt.
Grundsätzlich geht der Importer nach folgendem Muster vor:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: | <?xml version="1.0" encoding="utf-8"?> <import-definition xmlns="http://schema.programmfabrik.de/import-definition/0.1"> <actions> <!-- <empty/> --> <insert /> <delete /> <update /> </actions> <table name="bilder"> <restrict-import> <column name="reference_id"> <not-null/> </column> </restrict-import> <unique-keys> <unique-key> <column name="reference_id"/> </unique-key> </unique-keys> <filter-columns-output> <filter-column name="id"/> </filter-columns-output> <extra-columns> <extra-column name="kuenstler_reference_id" type="int4" /> </extra-columns> <lookups> <lookup other-table="kuenstler"> <other-column name="reference_id"> <input-column name="kuenstler_reference_id"/> </other-column> <set-column name="kuenstler_id"> <other-column name="id"/> </set-column> </lookup> </lookups> </table> <table name="bilder_revision"> <filter-columns-output> <filter-column name="id"/> </filter-columns-output> <unique-keys> <unique-key> <column name="bilder_id"/> <column name="version_no"/> </unique-key> </unique-keys> <extra-columns> <extra-column name="bilder_reference_id" type="int4" /> </extra-columns> <lookups> <lookup other-table="bilder"> <other-column name="reference_id"> <input-column name="bilder_reference_id"/> </other-column> <set-column name="bilder_id"> <other-column name="id"/> </set-column> </lookup> </lookups> </table> <table name="kuenstler"> <restrict-import> <column name="reference_id"> <not-null/> </column> </restrict-import> <unique-keys> <unique-key> <column name="reference_id"/> </unique-key> </unique-keys> <filter-columns-output> <filter-column name="id"/> </filter-columns-output> </table> </import-definition> |
empty | Diese Action dient zum Testen der XSL und XML Syntax, es wird keine Aktion durchgeführt. |
insert | Neue Datensätze werden angelegt. |
update | Veränderte Datensätze, die bereits in der Datenbank vorhanden sind, werden aktualisiert. |
delete | Datensätze, die in der Datenbank enthalten sind, aber nicht im Import gefunden und nicht ignoriert werden, werden gelöscht. |
In der Auflistung der Tabellen gibt es die folgenden steuernden Elemente:
restrict-import | Wenn Zeilen diese Spalten nicht matchen, werden die Zeilen beim Import ignoriert, d.h. bei einem vollen Import nicht gelöscht. |
unique-keys | Damit der Importer feststellen kann, ob eine Zeile neu geschrieben werden muss, oder aktualisiert werden soll, sucht der Importer in der Datenbank die Zeile mit Hilfe dieses Unique-Keys heraus. Die Angabe eines Unique-Keys ist zwingend. Der Unique-Key muss in der Datenbank existieren. |
filter-columns-output | Normalerweise baut der Importer alle INSERT und UPDATE Statements komplett für alle Spalten der Zeile zusammen, d.h. Spalten die sich nicht im zu importierenden XML befinden, werden explizit auf null gesetzt, es sei denn sie sind hier in filter-columns-output aufgelistet. Als Attribut kann ein name direkt angegeben werden, oder Spalten mit regexp ausgewählt werden. |
filter-columns-input | Normalerweise baut der Importer für alle im XML gefundenen Spalten eine Spalte in der temporären Import-Tabelle. Diese Spalte wird nicht angelegt, wenn sie in filter-columns-input aufgelistet ist. Als Attribut kann ein name direkt angegeben werden, oder Spalten mit regexp ausgewählt werden. |
include-columns-output | (ab der nächsten imexporter-Version) Wenn nur einige Spalten in der Datenbank geschrieben werden sollen, kann diese Positivliste verwendet werden. Die Namen der verwendeten Spalten werden entweder direkt (Attribut name) oder einen regulären Ausdruck (Attribut regex) angeben. |
include-columns-input | (ab der nächsten imexporter-Version) Wenn mehr als die Hälfte der Tabellenspalten nicht in der Import-Tabelle verwendet werden sollen, bietet sich eine Positivliste der zu verwendenden Spalten an. Damit werden nur die über ihren kompletten Namen (Attribut name) oder einen regulären Ausdruck (Attribut regex) beschrieben Spalten verwendet. |
extra-columns | Wenn das XML Spalten enthält, die nicht in der Datenbank-Tabelle vorhanden sind (z.B. um eine Referenz-Matching durchzuführen), so teilen Sie dies dem Importer mit der Angabe von extra-columns mit. Hierbei ist die Angabe eines PostgreSQL-Datentyps erforderlich. Sollten Sie die Spalte für eine Lookup benutzen, muss er denselben Typ haben, wie die entsprechende Spalte in der Datenbank-Tabelle auf der der Lookup durchgeführt wird. |
lookups | Mit lookups können Sie in der Datenbank etwas nachschauen und einen Wert korrespondierend zu einem gefundenen Eintrag im Rahmen des Imports umschreiben. Das bietet sich an, wenn z.B. die zu importierenden Daten eigenen Referenz-IDs benutzen, die dann auf easydb-IDs umgeschrieben werden müssen. Das Matching erfolgt über das Attribut other-table in der Tabelle in der easydb-Datenbank. Dabei wird in der Spalte other-column nach dem Wert der Spalte input-column aus der zum Import stehende Tabelle gesucht. Ist ein Eintrag gefunden, wird mit set-column angegeben welche Spalte in der easydb-Tabelle gesetzt wird. Der Wert steht in dem gefundenen Eintrag in der Spalte other-column. |
Derzeit können Sie keine Wiederholgruppen importieren, wenn diese nicht über einen eindeutigen Unique-Key verfügen (was in den meisten easydb-Wiederholgruppen der Fall ist). Sie benötigen in dem Fall, eine neue Spalte in der Wiederholgruppe, die einen Unique-Key herstellen kann. In unserem Beispiel ist das die Spalte version_no in der Tabelle bilder_revision.
Für unser Beispiel wird mit den folgendne Daten gearbeitet:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: | <?xml version="1.0" encoding="UTF-8" ?> <bilder> <bild> <reference>123</reference> <name>Mein erstes Bild</name> <kuenstler> <name>Horst Schramm</name> <reference>144</reference> </kuenstler> <standorte> <standort> <name>Europa > Deutschland > Berlin</name> <path> <name>Europa</name> <name>Deutschland</name> <name>Berlin</name> </path> </standort> </standorte> <versions> <version> <author>Tom Mueller</author> <comment>Initiale Version</comment> <date>2011-10-08 14:50</date> </version> <version> <author>Tom Mueller</author> <comment>Rechtschreibfehler korrigiert</comment> <date>2011-10-08 21:10</date> </version> <version> <author>Heike Mueller</author> <comment>Verberssungen im Detail.</comment> <date>2011-10-09 09:50</date> </version> </versions> </bild> <bild> <reference>124</reference> <name>Mein zweites Bild</name> <kuenstler> <name>Horst Müller</name> <reference>145</reference> </kuenstler> <versions> <version> <author>Tom Mueller</author> <comment>Initiale Version</comment> <date>2011-10-08 14:50</date> </version> <version> <author>Tom Mueller</author> <comment>Rechtschreibfehler korrigiert</comment> <date>2011-10-08 21:10</date> </version> <version> <author>Heike Mueller</author> <comment>Verberssungen im Detail.</comment> <date>2011-10-09 09:50</date> </version> </versions> </bild> <!-- <bild> <reference>124</reference> <name>Mein drittes Bild</name> <kuenstler> <name>Horst Schramm</name> <reference>144</reference> </kuenstler> </bild>--> </bilder> |
Das Format dieser Datei ist easydb unabhängig, es handelt sich hierbei um reines XSL.
Das Ziel der Transformation sind normalisierte Daten in einer relativen Strukur, d.h. es gibt Tabellen mit Spalten. Die Tabellen-Struktur ist jene, die in der easydb-Datenbank vorhanden sind. In diesem Schritt findet das eigentliche Mapping der Daten statt. Zum Aufbereiten der Daten sind ggfs. fundierte XSL-Kenntnisse erforderlich.
Für das hier besprochene Beispiel verwenden wir die folgende Datei:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: | <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns="http://schema.programmfabrik.de/imexport-data/0.1"> <xsl:output method="xml" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="bilder"> <dump> <table tablename="bilder"> <xsl:apply-templates select="bild"/> </table> <table tablename="kuenstler"> <xsl:apply-templates select="bild/kuenstler"/> </table> <table tablename="bilder_revision"> <xsl:apply-templates select="bild/versions/version"/> </table> </dump> </xsl:template> <xsl:template match="bild"> <row> <col name="reference_id"> <xsl:value-of select="reference/text()"/> </col> <col name="titel"> <xsl:value-of select="name/text()"/> </col> <col name="kuenstler_reference_id"> <xsl:value-of select="kuenstler/reference/text()"/> </col> </row> </xsl:template> <xsl:template match="bild/kuenstler"> <row> <col name="reference_id"> <xsl:value-of select="reference/text()"/> </col> <col name="name"> <xsl:value-of select="name/text()"/> </col> </row> </xsl:template> <xsl:template match="bild/versions/version"> <row> <col name="bilder_reference_id"> <xsl:value-of select="../../reference/text()"/> </col> <col name="author"> <xsl:value-of select="author/text()"/> </col> <col name="comment"> <xsl:value-of select="comment/text()"/> </col> <col name="created"> <xsl:value-of select="date/text()"/> </col> <col name="version_no"> <xsl:value-of select="count(preceding-sibling::*)"/> </col> </row> </xsl:template> </xsl:stylesheet> |
Die hier gezeigte XML-Datei wird aus den Beispiel-Daten und dem XSL erzeugt und dient als Input für den Datenbank-Import. Diese Datei können Sie mit XSLT-Tools wie z.B. xsltproc erzeugen:
xsltproc import_test.xsl import_test.xml > test.xml
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: | <?xml version="1.0"?> <dump xmlns="http://schema.programmfabrik.de/imexport-data/0.1"> <table tablename="bilder"> <row> <col name="reference_id">123</col> <col name="titel">Mein erstes Bild, wirklich, wirklich</col> <col name="kuenstler_reference_id">144</col> </row> <row> <col name="reference_id">124</col> <col name="titel">Mein zweites Bild</col> <col name="kuenstler_reference_id">145</col> </row> </table> <table tablename="kuenstler"> <row> <col name="reference_id">144</col> <col name="name">Horst Schramm</col> </row> <row> <col name="reference_id">145</col> <col name="name">Horst Müller</col> </row> </table> <table tablename="bilder_revisions"> <row> <col name="bilder_reference_id">123</col> <col name="author">Tom Mueller</col> <col name="comment">Initiale Version</col> <col name="created">2011-10-08 14:50</col> </row> <row> <col name="bilder_reference_id">123</col> <col name="author">Tom Mueller</col> <col name="comment">Rechtschreibfehler korrigiert</col> <col name="created">2011-10-08 21:10</col> </row> <row> <col name="bilder_reference_id">123</col> <col name="author">Heike Mueller</col> <col name="comment">Verberssungen im Detail.</col> <col name="created">2011-10-09 09:50</col> </row> <row> <col name="bilder_reference_id">124</col> <col name="author">Tom Mueller</col> <col name="comment">Initiale Version</col> <col name="created">2011-10-08 14:50</col> </row> <row> <col name="bilder_reference_id">124</col> <col name="author">Tom Mueller</col> <col name="comment">Rechtschreibfehler korrigiert</col> <col name="created">2011-10-08 21:10</col> </row> <row> <col name="bilder_reference_id">124</col> <col name="author">Heike Mueller</col> <col name="comment">Verberssungen im Detail.</col> <col name="created">2011-10-09 09:50</col> </row> </table> </dump> |
DROP DATABASE IF EXISTS import_test; CREATE DATABASE import_test; \c import_test; BEGIN; CREATE TABLE kuenstler ( id SERIAL PRIMARY KEY NOT NULL, name TEXT NOT NULL, reference_id INTEGER UNIQUE ); CREATE TABLE bilder ( id SERIAL PRIMARY KEY NOT NULL, kuenstler_id INTEGER NOT NULL REFERENCES kuenstler(id), reference_id INTEGER UNIQUE, titel TEXT NOT NULL ); CREATE TABLE bilder_revision ( id SERIAL PRIMARY KEY NOT NULL, bilder_id INTEGER NOT NULL REFERENCES bilder(id) ON DELETE CASCADE, version_no INTEGER NOT NULL, comment TEXT, author TEXT, created TIMESTAMP WITH TIME ZONE ); CREATE UNIQUE INDEX bilder_rev_uq ON bilder_revision(bilder_id, version_no); INSERT INTO kuenstler(id, name) VALUES (1, ‘kuenstler 1’); — INSERT INTO kuenstler(id, name) VALUES (2, ‘kuenstler 2’); — INSERT INTO kuenstler(id, name) VALUES (3, ‘kuenstler 3’); SELECT setval(pg_get_serial_sequence(‘kuenstler’, ‘id’), 3); INSERT INTO bilder(titel, kuenstler_id) VALUES (‘test 1’, 1); — INSERT INTO bilder(titel, id) VALUES (‘test 2’, 2); — INSERT INTO bilder(titel, id) VALUES (‘test 3’, 3); — SELECT * FROM bilder; — SELECT * FROM kuenstler; COMMIT;
Nachdem Import unserer Beispiel-Daten sind die Tabellen wie folgt gefüllt:
id | kuenstler_id | reference_id | titel ----+--------------+--------------+------------------- 1 | 1 | | test 1 2 | 4 | 123 | Mein erstes Bild 3 | 5 | 124 | Mein zweites Bild (3 rows)
id | bilder_id | version_no | comment | author | created ----+-----------+------------+-------------------------------+---------------+------------------------ 1 | 2 | 0 | Initiale Version | Tom Mueller | 2011-10-08 14:50:00+02 2 | 2 | 1 | Rechtschreibfehler korrigiert | Tom Mueller | 2011-10-08 21:10:00+02 3 | 2 | 2 | Verberssungen im Detail. | Heike Mueller | 2011-10-09 09:50:00+02 4 | 3 | 0 | Initiale Version | Tom Mueller | 2011-10-08 14:50:00+02 5 | 3 | 1 | Rechtschreibfehler korrigiert | Tom Mueller | 2011-10-08 21:10:00+02 6 | 3 | 2 | Verberssungen im Detail. | Heike Mueller | 2011-10-09 09:50:00+02 (6 rows)
id | name | reference_id ----+---------------+-------------- 1 | kuenstler 1 | 4 | Horst Schramm | 144 5 | Horst Müller | 145 (3 rows)