- 1 Intro
- 2 Anwendungsgebiete
- 2.1 XSLT - die Programmiersprache im XML Bereich
- 2.2 Aktuelle und vergangene Anwendungen
- 2.3 Professionelle XML Verarbeitung
- 2.4 Technische Dokumentation
- 3 Wichtige Konzepte
- 3.1 Push vs. Pull Stylesheets
- 3.2 Eindeutigkeit der Regelbasis
- 3.3 Namespaces
- 3.4 Schemata
- 3.5 Standards
- 3.5.1 DITA
- 3.5.2 DITA Inhaltsmodell
- 3.5.1 DITA
- 4 Ausgewählte Themen
- 4.1 Transformationen mit XSLT
- 4.1.1 Vortransformationen
- 4.1.2 Komplexe XML-2-XML Transformationen
- 4.1.2.8 Vererbung
- 4.1.2.8 Vererbung
- 4.1.3 XSLT Streaming
- 4.1.3.1 XSLT Akkumulator
- 4.1.3.2 XSLT Iterator
- 4.1.4 Reguläre Ausdrücke
- 4.1.5 Modus vs. Tunnel Lösung
- 4.1.6 Identifikation mit
generate-id()
- 4.1.6.4 XPath-Achsenbereich selektieren
- 4.1.6.4.1 Funktionen und Module
- 4.1.6.4.1 Funktionen und Module
- 4.1.6.4 XPath-Achsenbereich selektieren
- 4.1.7 Webservice Calls mit doc() und unparsed-text()
- 4.1.8 Stylesheet-Parameter auf der Kommandozeile
- 4.1.9 Leerzeichenbehandlung
- 4.1.10 Mit
translate
Zeichen ersetzen
- 4.1.10.1 Spass mit dem Sequenzvergleich
- 4.1.11 Character Mappings in der Ausgabe
- 4.1.12 JSON mit XSLT 1.0 und Python lxml
- 4.1.1 Vortransformationen
- 4.2 Abfragen mit XQuery
- 4.2.5 XQuery als Programmiersprache
- 4.2.5.3
if..then..else
Ausdrücke
- 4.2.5.3.2 SQL Views in MarkLogic
- 4.2.5.3
if..then..else
Ausdrücke
- 4.2.6 Hilfreiche XQuery Schippsel
- 4.2.5 XQuery als Programmiersprache
- 4.3 XML Datenbanken
- 4.3.1 Connector zu Marklogic in Oxygen
- 4.3.2 Bi-Temporale Dokumente
- 4.3.2.1 Anlegen des Testszenarios auf der ML Konsole
- 4.3.2.2 Ausführen einiger Beispiel-Queries
- 4.3.3 Webapps mit MarkLogic
- 4.3.3.5 Wikipedia Scrapper Applikation
- 4.3.3.5 Wikipedia Scrapper Applikation
- 4.3.4 Dokument-Rechte in MarkLogic
- 4.3.5 MarkLogic Tools
- 4.3.5.1 EXPath Konsole
- 4.3.5.2 mlcp - MarkLogic Content Pump
- 4.3.5.3 Deployment-Tools
- 4.4 XSL-FO mit XSLT1.x
- 4.5 Testing
- 4.5.1 Validierung mit Schematron
- 4.5.2 Erste Schritte mit XSpec
- 4.5.1 Validierung mit Schematron
- 4.6 Performanz-Optimierung
- 4.1 Transformationen mit XSLT
- 5 Zusätzliches Know-How
- 5.1 XML Editoren
- 5.2 Quellcode-Versionskontrolle
- 5.2.1 Kurze Geschichte zur Versionskontrolle Test
- 5.2.2 GIT Kommandos
- 5.2.1 Kurze Geschichte zur Versionskontrolle Test
- 5.1 XML Editoren
- 6 Glossary
- 7 Tektur CCMS
4.3.2 Bi-Temporale Dokumente
Wenn wir zwischen der Zeit in der das Dokument, bspw. ein Vetrag
in der DB angelegt wird, und der Zeit in der ein Vetrag zwischen zwei
Vetragspartnern abgeschlossen wird unterscheiden, dann betrachten
wir zwei Zeitachsen.
-
die gültige Zeit (Valid Time)
-
die Systemzeit (System Time)
Für die Vetragspartner ist nur die gültige Zeit relevant. Das Zeitfenster
zwischen gültiger Zeit und Systemzeit ist jedoch in manchen Fällen
ausschlaggebend.
Bsp: Kürzlich wurde
meine Geldbörse mit meinem Perso geklaut. Beim Austellen eines vorläufigen
Ausweises wurde ich schriftlich darauf hingewiesen, dass nun mein Perso
bei Interpol zur Fahndung ausgeschrieben ist.
Kurze Zeit später fand ein netter Herr die Geldbörse (ohne Geld aber
mit allen Papieren) in seinem Garten. Bei einer anschliessenden Busfahrt mit einem
Fernbus, wurde ich bei einer Zollkontrolle festgehalten, da das System der Polizei noch nicht aktualisiert war.
Ich nehme an, dass nach meiner Unschuldsbekundung der Vorgang auch
auf Seiten des Polizeicomputers aktualisiert wurde. Nun könnte man zwei Fragen
stellen:
1. | Ist das Festhalten seitens der Zollbeamten rechtens? |
2. | Habe ich mich durch ein verspätetes Anzeigen des Funds schuldig gemacht? |
Beachte, dass man diese Fragen auch noch nach 10 Jahren stellen
könnte und das - bei meinem Pech in diesen Angelegenheiten - so ein Vorfall auch noch öfters passieren könnte...
Um diese Fragen zu beantworten, müsste unsere Datenbank in der Lage sein,
eine bitemporale Query ↗ auszuführen. Zunächst registerieren wir den Vorgang
des Persoverlustes in unserer Marklogic Datenbank:
Da wir hier auf einer XML Datenbank arbeiten, sprechen wir von einem Dokument,
wenn wir einen Datensatz meinen.
Der Datensatz bzw. das Dokument wird nicht aktualisiert, sondern stattdessen das Dokument mit den aktualisierten Daten in einer neuen Version angelegt.
Auf diese Weise bleibt die Änderungshistorie erhalten.
xquery version "1.0-ml"; import module namespace temporal = "http://marklogic.com/xdmp/temporal" at "/MarkLogic/temporal.xqy"; let $root := <vorgang> <perso-id>XYZ</perso-id> <name>Alex Düsel</name> <status>gestohlen</status> </vorgang> let $options := <options xmlns="xdmp:document-insert"> <metadata> <map:map xmlns:map="http://marklogic.com/xdmp/map"> <map:entry key="validStart"> <map:value>2019-02-01T08:23:11</map:value> </map:entry> <map:entry key="validEnd"> <map:value>9999-12-31T11:59:59Z</map:value> </map:entry> </map:map> </metadata> return temporal:document-insert("/perso-verluste", "duesel_alex_270774.xml", $root, $options)
Unser Enddatum liegt in ferner Zukunft sicherzustellen, dass der Vorgang auf unbestimmte Zeit
im System bleibt.
Drei Tage später hatte ich meinen Ausweis wieder und der Vorgang wurde vier Tage später,
mit dem Status "gefunden" im Polizeicomputer aktualisiert:
xquery version "1.0-ml"; import module namespace temporal = "http://marklogic.com/xdmp/temporal" at "/MarkLogic/temporal.xqy"; let $root := <vorgang> <perso-id>XYZ</perso-id> <name>Alex Düsel</name> <status>gefunden</status> </vorgang> let $options := <options xmlns="xdmp:document-insert"> <metadata> <map:map xmlns:map="http://marklogic.com/xdmp/map"> <map:entry key="validStart"> <map:value>2019-02-06T08:00:00<map:value> </map:entry> <map:entry key="validEnd"> <map:value>9999-12-31T11:59:59Z</map:value> </map:entry> </map:map> </metadata> return temporal:document-insert("/perso-verluste", "duesel_alex_270774.xml", $root, $options)
Nach der Aktualisierung enthält unsere Datenbank logisch gesehen drei Dokumente zu diesem Vorgang,
die über eine Query gesucht werden können:
1. | Das Originaldokument, es ist vom 1.2.2019 bis zum 5.2.2019 im System aktiv |
2. | Die Aktualisierung, sie ist ab dem 6.2.2019 aktiv |
3. | Ein "Split"-Dokument, das aus der verspäteten Aktualisierung resultiert. Es ist ab dem 6.2.2019 im System aktiv, und zeigt den Zeitraum über einen Tag, vom 4.2.2019 bis 5.2.2019 - in dem ich ohne Perso registriert war, ihn aber tatsächlich schon wieder hatte. |
Im Gegensatz zu einer herkömmlichen Datenhaltung, bei der ein Datensatz aktualisiert wird - ggf. noch eine neue
Version angelegt wird - wird beim Dokument-basierten Ansatz mit bi-temporaler Datenhaltung jede Transaktion separat
abgespeichert.
Das ist vergleichbar mit einer Simulation des tatsächlichen Papierverkehrs bei buchhalterischen Tätigkeiten.
Die Abfrage so einer Datenbank ist dadurch nicht einfacher. Drei Queries, die jeweils eines dieser drei
Dokumente zurückgeben, könnten bspw. so aussehen:
Rückgabe des Originals
xquery version "1.0-ml"; cts:search(fn:doc(), cts:period-range-query( "system", "ISO_CONTAINS", cts:period(xs:dateTime("2019-02-02T00:00:00"), xs:dateTime("2019-02-03T23:59:59")) )
Hier wird geprüft, ob ein Dokument im System aktiv war, dass den Zeitraum vom 2.3. bis zum 3.3. umfasste (
ISO_CONTAINS
). Diese Query ist erfolgreich und gibt das Original-Dokument des Vorgangs zurück: In diesem Zeitraum war ich also mit gestohlenem Perso registriert.
Rückgabe des Split-Dokuments
xquery version "1.0-ml"; cts:search(fn:doc(), cts:period-range-query( "valid", "ALN_FINISHES", cts:period(xs:dateTime("2019-02-06T08:00:00"), xs:dateTime("2019-02-06T08:00:00")) ))
Bei dieser Query wird geprüft, ob es ein Dokument gibt, dass zu einem bestimmten Datum auf inaktiv gesetzt wurde (
ALN_FINISHES
) - Das Split-Dokument wird automatisch auf inaktiv gesetzt, wenn die neue Version angelegt wird. Unser Suchdatum wäre also folgendes
2019-02-06T08:00:00
.
Rückgabe von Split und neuer Version
xquery version "1.0-ml"; cts:search(fn:doc(), cts:period-range-query( "system", "ALN_AFTER", cts:period(xs:dateTime("2019-02-05T11:00:00"), xs:dateTime("2019-02-05T11:20:00")) ))
Hier wird geprüft ob es Dokumente gibt, die nach einer bestimmten Zeitspanne im System aktiv waren. Man beachte hier, dass eine Periode angegeben ist, obwohl nur ein Datum notwendig wäre. Der Vergleichsoperator hierzu heisst
ALN_AFTER
.
Rückgabe von aktueller Version
xquery version "1.0-ml"; cts:search(fn:doc(), cts:period-compare-query( "system", "ISO_CONTAINS", "valid" ))
Die aktuelle Version kann in Erfahrung gebracht werden, indem geprüft wird, welche gültigen Dokumente innerhalb der Systemzeitspanne liegen. Das kann nur die aktuelle Version sein. Frühere gültige Versionen und Split-Dokumente wären vor der Systemzeit-Spanne.
Die letzte Version eines Dokuments kann aber auch einfach über ein
latest
flag in Erfahrung gebracht werden:
xquery version "1.0-ml"; cts:search(fn:doc(), cts:and-query(( cts:collection-query(("koolorder.xml")), cts:collection-query(("latest")))))
Weiterführende Links