Dokumentationen zu LibreOffice unter de.libreoffice.org

Copyright
Dieses Dokument unterliegt dem Copyright © 2018. Die Beitragenden sind unten aufgeführt.
Sie dürfen dieses Dokument unter den Bedingungen der GNU General Public License (http://
www.gnu.org/licenses/gpl.html), Version 3 oder höher, oder der Creative Commons Attribution
License (http://creativecommons.org/licenses/by/3.0/), Version 3.0 oder höher, verändern und/oder weitergeben.
Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutzt.
Fast alle Hardware- und Softwarebezeichnungen und weitere Stichworte und sonstige Angaben,
die in diesem Buch verwendet werden, sind als eingetragene Marken geschützt.
Da es nicht möglich ist, in allen Fällen zeitnah zu ermitteln, ob ein Markenschutz besteht, wird
das Symbol (R) in diesem Buch nicht verwendet.
AutorenRobert Großkopf
Mitwirkende
Klaus-Jürgen Weghorn

Susanne Mohn

Rückmeldung (Feedback)Kommentare oder Vorschläge zu diesem Dokument können Sie in deutscher Sprache an die
Adresse discuss@de.libreoffice.org senden.

Vorsicht
Alles, was an eine Mailingliste geschickt wird, inklusive der E-Mail-Adresse und anderer
persönlicher Daten, die die E-Mail enthält, wird öffentlich archiviert und kann nicht
gelöscht werden. Also, schreiben Sie mit Bedacht!

Datum der Veröffentlichung und Softwareversion
Veröffentlicht am 01.08.2023. Basierend auf der Version LibreOffice 7.6.

Dokumentationen zu LibreOffice unter de.libreoffice.org

Inhalt
Einleitung .......................................................................................................................... 4
Ein XML-Formular Schritt für Schritt .................................................................................... 5
Datensammlung formatiert ............................................................................................... 14
Erstellen einer XSL-Datei zur Formatierung .......................................................................................... 15
Kopieren der neuen Daten in eine dauerhafte Datendatei .................................................................... 16
Formulareingabe optimieren ............................................................................................. 17
Versandmethoden für den Formularinhalt .......................................................................... 18
POST-Methode ....................................................................................................................................... 18
GET-Methode ......................................................................................................................................... 19
PUT-Methode ......................................................................................................................................... 20
Versand des gesamten Formulars per Mail ........................................................................................... 21
Komplexere Formulardefinition ......................................................................................... 24
Definition der Instanzen ........................................................................................................................ 24
Daten verschicken ................................................................................................................................ 27
Bindungen für Formularfelder ............................................................................................................... 28
Formularfelder ...................................................................................................................................... 29
Eingabebedingungen ............................................................................................................................ 32
Erforderlich ...................................................................................................................................... 32
Relevant ........................................................................................................................................... 33
Einschränkung ................................................................................................................................. 34
Schreibschutz und Berechnen .......................................................................................................... 35
Formatierte Ausgabe in XML-Dokumenten ............................................................................................ 37
XML-Formulare mit Datenbankanbindung nutzen ............................................................... 38
Makrozugriff über die Bindungen des XML-Formulars ........................................................................... 38
Base-Tabellen erstellen ......................................................................................................................... 40
Makrozugriff auf die Base-Datenbank ................................................................................................... 40
Abgespeicherte XML-Dateien einlesen ............................................................................... 44
Anhang ............................................................................................................................ 46
Submissions-Methoden ......................................................................................................................... 46
Xforms Funktionen ................................................................................................................................ 46
XPath Operators .................................................................................................................................... 46
Datentypen ........................................................................................................................................... 47

3

Einleitung
Mit XML-Formulardokumenten werden Formulare erstellt, die XML-Dateien erzeugen. Diese werden in ihrer entsprechenden Struktur mit Daten versehen, die sowohl in der Formulardatei als
auch als *.xml-Datei z. B. lokal gespeichert werden. Außerdem kann so ein Formular dazu
genutzt werden, Daten in einer XML-Datensammlung zu speichern und über einen Browser ineiner sinnvollen Übersicht auszugeben.
Für das Ausführen eines mit LibreOffice erstellten XML-Formulars ist eine Installation vonLibreOffice erforderlich. Mit anderen Programmen als den mit LibreOffice verwandten OfficeProgrammen ist die Nutzung von XML-Formulardokumenten nicht möglich.
In dieser Dokumentation geht es darum, zuerst einmal ein einfaches Formular erstellen zu können. Anschließend wird gezeigt, wie die Inhalte eines solchen Formulars weiter genutzt werden
können und zu größeren Datensammlungen, auch über das Internet mit einem Server, zusammengefasst werden können.
Vorteile von XML-Formularen gegenüber anderen Formularen in LibreOffice:•

Die Eingabe in ein Feld kann sehr genau durch entsprechende Typvorgaben eingegrenzt
werden.

•Felder, bei denen eine Eingabe notwendig ist, sind durch eine entsprechende rote
Umrandungsfarbe deutlich erkennbar.

•

Felder können in Abhängigkeit von anderen Feldern als notwendig oder nicht notwendig
definiert werden.

•

Felder können als Berechnungsfelder anderer Felder erstellt werden.

•

All dies geschieht unmittelbar während der Eingabe. Falsches Ausfüllen der Formulare
kann also sehr stark eingeschränkt werden.

Tipp
Um XML-Formulardokumente erstellen und verwalten zu können – und damit Grundlagenwissen dieser Dokumentation – sind das Verständnis und die sichere Handhabungvon:• Erstellen und Bedienen von Formularen in LibreOffice•Beherrschen von Formularsteuerelementen in LibreOffice• Erstellen und Bedienen von Makros in LibreOffice.
Sollten Sie hier noch nicht so firm sein, finden Sie weitere Hinweise in den ErsteSchritte-Handbüchern sowie im Base- und im Macro-Handbuch:https://de.libreoffice.org/get-help/documentation/

HinweisXML-Dateien, also auch die Daten, die über XML-Formulare verarbeitet werden, sindnicht weiter gesichert. Die Dateien sind im Klartext lesbar, können im Browser übersichtlich dargestellt werden und enthalten standardmäßig keinen weiteren Schutz. Bei
Formularen, die den Inhalt über das Netz verschicken, muss der Schutz entsprechend in
die Auswertung eingebaut werden. Werden Daten über Email weitergeleitet, so sollten
die Mails möglichst verschlüsselt werden.

Einleitung

4

Hinweis
XML-Dateien, die das Formular erzeugt, haben den folgenden Aufbau:1
001
002
003
004
005

<?xml version="1.0" encoding="UTF-8"?><instanceData><Vorname>Lieschen</Vorname><Nachname>Müller</Nachname></instanceData>

Einem einführenden Tag, der die Datei als XML-Datei kennzeichnet und zusätzlich nochden verwendeten Zeichensatz enthält, folgt ein Element, das die gesamten Datenumfasst. In der Regel gibt es zu jedem Element einen Starttag und einen Endtag, wobei
der Endtag an dem / zu erkennen ist. Text, der zwischen diesen Tags steht, enthält die
Daten, hier also den Vornamen «Lieschen» und den Nachnamen «Müller».

Ein XML-Formular Schritt für Schritt
LibreOffice wird gestartet. Über Datei → Neu → XML-Formulardokument wird eine Writeransicht
zusammen mit der für XML-Formulare erforderlichen Seitenleiste erstellt.

Das Formular wird im Entwurfsmodus geöffnet:

Wird das Dokument abgespeichert und erneut geladen, so wird das Formular zur Dateneingabe
geöffnet. Zum weiteren Bearbeiten muss der Entwurfsmodus ein/aus eingeschaltet werden.
1

Siehe: https://de.wikipedia.org/wiki/Extensible_Markup_Language

Ein XML-Formular Schritt für Schritt

5Dieser Entwurfsmodus ist nicht identisch mit dem Entwurfsmodus, der über die Symbolleiste
Formular-Steuerelemente oder über Formular → Entwurfsmodus erreicht werden kann.

Wird die Symbolleiste für die Formular-Steuerelemente nicht angezeigt, so kann diese überAnsicht → Symbolleisten → Formular-Steuerelemente eingeblendet werden.

In dem Reiter Instance 1 liegt bereits das umfassende Element instanceData. Diesem Element
werden im folgenden zwei gleichberechtigte Elemente hinzugefügt.

Ein XML-Formular Schritt für Schritt

6Der beim Hinzufügen der Elemente erscheinende Dialog wird auf jeden Fall in der Eigenschaft
Name bearbeitet. Hier sind die Untergliederungen «Vorname» und «Nachname» hinzugefügt
worden. Dadurch ist die komplette durch dieses Formular zu erstellende XML-Datei definiert.
Die weiteren Eigenschaften des Dialogs können auch in den Bindungen oder im Formularfeld
eingetragen werden. Sie werden durchgängig synchron gehalten.

Im Reiter Übermittlungen wird eine Versandart hinzugefügt. In früheren Versionen vonLibreOffice stand hier der englische Begriff «Submissions», für kurze Zeit auch die nicht passende deutschsprachige Übersetzung «Vorlagen».

Die Übermittlung (Submission) wird mit dem Namen «Absenden», dem Pfad für die Aktion auf
dem lokalen Rechner und der Methode → Put (siehe: PUT-Methode) versehen. Nach dem«Absenden» wird das bisherige Dokument mit dem neuen Inhalt überschrieben: Ersetzen →Dokument.
Ein XML-Formular Schritt für Schritt

7

Die entsprechenden Einträge für die Submission lassen sich unter dem Reiter Übermittlungen(Submissions) anzeigen.

Bindungen werden standardmäßig direkt hinzugefügt. Nur so ist es möglich, die Formularfelder
mit den entsprechenden Instanzen zu koppeln. So sind in obigem Screenshot bereits die beiden
Bindungen für «Vorname» und «Nachname» zu sehen. Sollten die Bindungen nicht zu sehen
sein so hilft es auch, das Formular zu speichern, zu schließen und neu zu starten.
Hilft dies auch nicht, so kann eine Bindung hinzugefügt, die den Angelpunkt zu den geplanten
Formularfeldern darstellt.

Ein XML-Formular Schritt für Schritt

8

Die Bindungen werden automatisch durchnummeriert, können natürlich auch mit separaten
Namen versehen werden. So wurde oben die leere Bindung, die aus dem Klick auf«instanceData» entstanden ist, gelöscht und die Benennung der anderen Bindungen angepasst. Wird hier der gleiche Ausdruck wie bei den Instanzen als Bindungsausdruck eingegeben,
so erfolgt die entsprechende Koppelung zu den Instanzen.
Jede Bindung wird mit entsprechenden Eigenschaften versehen. Diese können aber auchbereits bei der Festlegung der Instanzen mit dem gleichen Dialog erstellt werden. Gegebenenfalls können sie auch noch in den Formularfeldern nachgetragen werden.
Wichtig ist hier, dass Einstellungen → Datentyp mit einem entsprechenden Typ versehen wird.
Erst so kann bei der Eingabe überprüft werden, ob die Eingabe einen Sinn ergibt. Bei einfachen
Zeichenketten macht sich das nicht bemerkbar, aber falsch geschriebene Datumseingabenkönnen so z. B. verhindert werden.

Wird später versucht, Inhalt mit einem anderen Datentyp über ein Formularfeld einzugeben, so
wird das Formularfeld rot umrandet und beim Überfahren mit der Maus eine Meldung ausgegeben. Auch der Versand wird mit einer Fehlermeldung versehen. Allerdings schützt diese Einstellung letztlich nicht davor, bewusst falsch eingegebene Formate zu unterdrücken.
Für viele Funktionen besser geeignet ist daher das darauf zugeschnittene Formularfeld, das vonvornherein die Dateneingabe steuert und falsche Werte gar nicht erst akzeptiert. Das Textfeld
hingegen lässt erst einmal alle Eingaben zu und zeigt mit dem roten Rand, dass da etwas nicht
stimmt.

Ein XML-Formular Schritt für Schritt

9Aus den Formular-Steuerelementen2 wird das Textfeld ausgesucht. Im Gegensatz zu Datenbanken erfolgt jetzt im Reiter Daten eine Verknüpfung zu dem Datenmodell.
Nur Formularfelder, die eine Verknüpfung zu dem Datenmodell ermöglichen, können auch ohne
Makros genutzt werden. Dies sind:
Formularfeld
TextfeldGeeignet für …
Das Allroundfeld für die Eingabe jeden Datentyps. Es kann alle
Daten, die im XML-Formular eingelesen wurden, genau so wiedergeben, wie sie in der entsprechenden *.xml-Datei auch geschrieben werden.
Nachteil ist, dass hier strikt die Formatvorgabe der *.xml-Datei
beachtet werden muss. Ein Datum kann nicht in der deutschen
Schreibweise eingegeben werden. Besonders kompliziert wäre die
Eingabe eines Wertes für den Datentyp «Datum und Zeit».

2

Zu Formularsteuerelementen siehe auch das Erste-Schritte-Handbuch sowie das Base-Handbuch:https://de.libreoffice.org/get-help/documentation/

Ein XML-Formular Schritt für Schritt

10Numerisches Feld

Nur für die Datentypen «Dezimal», «Doppelte Genauigkeit» («Double»), «Fließkomma», «Jahr», «Monat» und «Tag» geeignet. Es gibt
grundsätzlich Zahlen mit 2 Nachkommastellen aus. Stören dieseAngaben oder zeigen sie zu wenig Nachkommastellen, so sollte
das formatierte Feld benutzt werden.

Zeitfeld

Nur für den Datentyp «Zeit» gedacht. Ein Zeitformat kann so vorgegeben werden dass entweder nur Stunden und Minuten oder
Stunden, Minuten und Sekunden eingegeben werden können. Die
Maximalzeit ist < 24:00:00.

Datumsfeld

Nur für den Datentyp «Datum» gedacht. Ein Datumsformat kannin vielen unterschiedlichen Schreibweisen vorgegeben werden.
Außerdem kann das Feld zur Datumsauswahl mit der Einstellung
Aufklappbar → Ja auf einen Kalender zugreifen.

Formatiertes Feld

Das Allroundfeld schlechthin. Hier sind alle Datentypen möglich.
Auch die entsprechenden Formatierung kann erstellt werden.
Es ist das einzige Feld, das dem Datentyp «Datum und Zeit» eine
Eingabe ermöglicht, die nicht an die *.xml-Vorlage gehalten ist.
Es ist das einzige Feld, bei dem für Zahleneingaben die Anzeige
der Nachkommastellen beeinflussen kann.
Es ist auch das einzige Feld, das Währungsangaben im Felderlaubt und daraus einfache Dezimalzahlen für den xml-Export
erstellt.

Markierfeld

Nur für den Datentyp «Ja/Nein (Boolean)» geeignet. Als Referenzwert sollte schlicht '1' für 'Ja' und '0' für 'Nein' vorgewählt werden.

Optionsfeld

Nur für den Datentyp «Ja/Nein (Boolean)» geeignet. Bei gleicher
Bezeichnung werden die Optionsfelder zusammen gruppiert und
nur eins der Felder gibt einen entsprechenden Wert an das XMLFormular weiter.

Listenfeld

Das Listenfeld kann direkt über Allgemein → Listeneinträge mit
Einträgen versorgt werden. Es kann auch in XML-Formularen überein zusätzliches Datenmodell, das die auswählbaren Einträge enthält, bestückt werden. Siehe dazu das Kapitel Formularfelder.
Eine Auswahl mehrere Werte über Allgemein → Mehrfachauswahl
ist nicht möglich.

Kombinationsfeld

Sind neben auswählbaren Einträgen auch neue Einträge
gewünscht, so ist das Kombinationsfeld passend. Das Kombinationsfeld kann direkt über Allgemein → Listeneinträge mit Einträgen
versorgt werden. Es kann auch in XML-Formularen über ein zusätzliches Datenmodell, das die auswählbaren Einträge enthält,
bestückt werden. Siehe dazu das Kapitel Formularfelder.

Schaltfläche

Die Schaltfläche ist zum Versand der Daten notwendig. Beide
Schaltflächen bieten eine Verbindung zu den vorgesehenen Versandarten an.

grafische Schaltfläche

HinweisDie Formular-Steuerelemente werden hier nicht kleinschrittig erklärt. Hierzu sollte das
Base-Handbuch zu Rate gezogen werden.
Assistenten, die bei Base-Formularen funktionieren, starten bei XML-Formularen nicht.
Sie wurden speziell auf die Zusammenarbeit mit Datenbanken erstellt.

Ein XML-Formular Schritt für Schritt

11

Tipp
Lässt sich ein Formular-Steuerelement nicht aufziehen, so kann dies an der fehlenden
Formulardefinition liegen. Über den Formularnavigator muss, wie bei Base-Formularen,ein Formular erstellt werden – auch wenn es keinen Inhalt hat. Dieses Formular sollte
bei XML-Formulardokumenten allerdings automatisch erstellt werden.

In diesem Beispiel steht nur das Model 1 zur Verfügung. Bindung lässt mit einem Auswahlfeld
die Auswahl der beiden definierten Bindungen zu, hier also von Bindung 1. Die restlichen Einträge spiegeln die Definition der Bindung wieder.

Dem Formular wird ein Button hinzugefügt. In den allgemeinen Eigenschaften (sehr weit unten)
wird hier die Aktion → Formular übertragen ausgewählt. In dem Feld Übermittlungen (Submission) ist jetzt [Model 1] Absenden verfügbar.

Ein XML-Formular Schritt für Schritt

12Wird jetzt über die Symbolleiste der Entwurfsmodus des Formulars ausgeschaltet, so ist die Eingabe von Daten in das Formular möglich. Durch die rote Umrandung und die Zusatzinformation
weist das Formular darauf hin, dass in den Feldern auf jeden Fall eine Eingabe erforderlich ist.
Ist eine Eingabe erfolgt und steht der Cursor nicht in dem Feld, so wird die Umrandung in dervoreingestellten Farbe gezeigt. Steht der Cursor noch in dem Feld, so erscheint das Feld mit
blauer Umrandung.

Nach erfolgter Eingabe und dem Absenden bleiben die Daten in dem Formular stehen. Unter
dem Reiter Instance 1 sind jetzt die Inhalte der Untergliederungen Vorname und Nachname zu
erkennen. Die Daten wurden in die definierte XML-Datei geschrieben und über das Formularwieder ausgelesen. Sie bleiben auch in dem Formulardokument weiter erhalten. Das Formularzurücksetzen kann hier über ein Makro für alle Felder oder jeweils über das Löschen des entsprechenden Elementes in der Instanz erfolgen. Der einfache Nutzer bekommt allerdings diesen Datennavigator nicht zu Gesicht und kann die Elemente in dem Formular entsprechend nur
leeren.

HinweisÄnderungen am Formularinhalt werden nicht automatisch vom Writer registriert. Siewerden trotzdem über Datei → Speichern mit abgespeichert. Ohne diese Speicherung
erscheint das Formular beim nächsten Mal wieder mit den alten Daten.

Die Formulardatei ist eine gepackte Datei. In ihr befinden sich viele verschiedene Dateien,
unter anderem auch die Datei «content.xml». In dieser «content.xml» ist das gesamte Formularverzeichnet. Auch die Daten sind dort im xml-Format abgespeichert. Wird also nur das Formularbenötigt und ist keine weitere Datenverarbeitung geplant, so reicht es aus, das Formular ohne
Ein XML-Formular Schritt für Schritt13jeden Eintrag für das Absenden einfach per Datei → Senden → Dokument als E-Mail… weiter zu
schicken.

Die XML-Datei «Beispiel.xml» weist zwei Zeilen auf. Sie startet mit der Definitionszeile undschreibt dann alle folgenden Einträge des Elements «instanceData» in eine Zeile.

Wird die Datei mit Firefox geöffnet, so erkennt Firefox den Aufbau der XML-Datei und stellt sie
entsprechend gegliedert dar. Firefox fehlen hier lediglich Style-Informationen, die statt der
Baum-Ansicht eine nutzerfreundlichere Ansicht bieten.

Datensammlung formatiert
Schöner wäre es natürlich, wenn Firefox Style-Informationen erhalten würde und nicht nur die
aktuellen Daten gesammelt würden. Das sähe dann beispielsweise so aus:Datensammlung formatiert

14

Damit Daten formatiert angezeigt werden muss die *.xml-.Datei auf eine *.xls-Datei zugreifen.
Außerdem muss die *.xml-Datei über einen Webserver aufgerufen werden. Beim direkten Aufruf im Dateisystem funktioniert die Verbindung nicht.

Erstellen einer XSL-Datei zur Formatierung
Die XML-Datei bezieht seine Formatierungen aus einer Datei mit separaten Formatanweisungen. Die Datei «Daten_Start_formatiert.xsl» hat die folgende Struktur:
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026

<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="/"><HTML><Head><Title>XML-Formular</Title></Head><Body><H2>Daten aus dem XML-Formular</H2><table><tr><th>Nachname</th><th>Vorname</th></tr><xsl:for-each select="Data/instanceData"><xsl:sort select="Nachname" order="ascending" data-type="text" /><tr><td><xsl:value-of select="Nachname"/></td><td><xsl:value-of select="Vorname"/></td></tr></xsl:for-each></table></Body></HTML></xsl:template></xsl:stylesheet>

Die Datei enthält innerhalb der Tags, die für die XSL-Datei notwendig sind, einen Aufbau wie
eine einfache HTML-Datei. Diese HTML-Datei besteht aus einer Überschrift und einer Tabelle mit
den Spaltentiteln «Nachname» und «Vorname».
In einer xsl:for-each-Schleife wird aus der XML-Datei alles ausgelesen, was sich innerhalb
des Bereiches instanceData befindet. Da instanceData mehrmals vorkommt, muss hier die
Schleife erfolgen.
Mit der xsl:sort-Anweisung werden die Daten, die sich in den instanceData-Bereichen befinden, nach dem Nachname aufsteigend sortiert.
Aus den Feldern Nachname und Vorname innerhalb von instanceData werden die entsprechenden Werte ausgelesen und in der Tabellenzeile dargestellt.
Die XML-Datei «Daten_Start_formatiert.xml» weist den folgenden Inhalt auf:
001
002
003
004
005
006
007
008
009
010
011

<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="./Daten_Start_formatiert.xsl" ?><Data><instanceData><Vorname>Robert</Vorname><Nachname>Großkopf</Nachname></instanceData><instanceData><Vorname>Jutta</Vorname><Nachname>Schön</Nachname></instanceData><instanceData><Vorname>Ammon</Vorname><Nachname>Düül</Nachname></instanceData><instanceData><Vorname>Nick</Vorname><Nachname>Knatterton</Nachname></instanceData><instanceData><Vorname>Silvia</Vorname><Nachname>Bach</Nachname></instanceData><instanceData><Vorname>Rob</Vorname><Nachname>van Buur</Nachname></instanceData><instanceData><Vorname>Bob</Vorname><Nachname>Baumeister</Nachname></instanceData></Data>In der zweiten Zeile dieser Datei wird darauf hingewiesen, dass die Darstellung in einer separaten Datei «Daten_Start_formatiert.xsl» definiert ist. Diese Datei liegt direkt im gleichen Ver-

Datensammlung formatiert

15

zeichnis wie die *.xml-Datei. Die Hauptinstanz <Data> darf hier nur einmal vorkommen, wieauch <instanceData> nur einmal in «Daten.xml» vorkommt.
Diese XML-Datei wird mit Hilfe eines Makros mit neuen Datensätzen aus der Datei«Daten_Start.xml» versorgt, die jeweils als neuer Tag <instanceData> als letzter Datensatz
angehängt werden. Die Datei «Daten_Start.xml» ist dabei die, die das Formular standardmäßigüber die Einträge von Vorlagen (Submissions) erstellt.

Kopieren der neuen Daten in eine dauerhafte Datendatei
Eine Kopie der Daten kann entweder händisch oder über ein Makro erfolgen. Das folgenden
Makro ist an den Button des Formulars mit dem Ereignis → Maustaste losgelassen verknüpft.3
001
002
003
004

SUB DatenNachXmlDatei(oEvent AS OBJECT)
DIM a()
DIM b()
stInstance = oEvent.Source.Model.Tag

Zuerst werden die Variablen definiert. Hier sind, im Gegensatz zum Quelltext, nur die unbedingt
notwendigen Definitionen der Arrays aufgeführt, die zum Auftrennen von Texten benötigt werden.
Anschließend wird aus den Zusatzinformationen (Tag) des Buttons der Name der Instanz ausgelesen. In dem Beispiel steht dann hier «Data».
005
006
007
008

oDoc = ThisComponent
stDir = Left(oDoc.Location,Len(oDoc.Location)-Len(oDoc.Title))
stFileTmp = stDir & "Daten_Start.xml"
stFileData = stDir & "Daten_Start_formatiert.xml"

Aus dem aktuellen Formular wird der Pfad ausgelesen, indem einfach der Dateiname abgetrennt wird. Dann werden die Datenquelle «Daten_Start.xml» und das Ziel für die Daten«Daten_Start_formatiert.xml» mit dem Pfad verbunden. Beide Dateien befinden sich also im
gleichen Verzeichnis wie die Formulardatei. «Daten_Start.xml» wird allerdings bei jeder Neueingabe vom Formular aus komplett überschrieben. Hier können also nicht Daten hinzugefügt werden.
009
010
011
012
013
014
015
016
017

oFileAccess = createUnoService("com.sun.star.ucb.SimpleFileAccess")
IF oFileAccess.exists(stFileTmp) THEN
oInputStream = createUnoService("com.sun.star.io.TextInputStream")oFile = oFileAccess.OpenFileReadWrite(stFileTmp)
oInputStream.SetInputStream(oFile.getInputStream)
DO WHILE NOT oInputStream.isEOF
stTmp = stTmp & oInputStream.ReadLine()
LOOP
oInputStream.closeInput

Mit einem Uno-Service wird auf den SimpleFileAccess zugegriffen. Mit diesem wird die Datei«Daten_Start.xml» zeilenweise ausgelesen und in der Variablen stTmp zusammengefasst.
Anschließend wird der Datenfluss beendet.
Die Variable stTmp wird aufgesplittet, so dass schließlich nur noch der Inhalt in stTmpData übrig
bleibt, der in der Datei «Daten_Start.xml» nach dem mit «?>» endenden Tag steht.
018
019

a = Split(stTmp,"?>")
stTmpData = a(1)Wie bei der ersten Datei wird jetzt auch die Datendatei «Beispiel_formatiert.xml» ausgelesen.
Allerdings wird der beim Auslesen abgeschnittene Zeilenumbruch jedes Mal wieder mit
CHR(13)&CHR(10) hinzugefügt.
020
021
022
023
024

3

IF oFileAccess.exists(stFileData) THEN
oInputStream = createUnoService("com.sun.star.io.TextInputStream")oFileData = oFileAccess.OpenFileReadWrite(stFileData)
oInputStream.SetInputStream(oFileData.getInputStream)
DO WHILE NOT oInputStream.isEOF

Siehe Base-Handbuch, Kapitel «Makros» (https://de.libreoffice.org/get-help/documentation/ )Datensammlung formatiert

16

025
026
027

stDataOld = stDataOld & oInputStream.ReadLine() & CHR(13) & CHR(10)LOOP
oInputStream.closeInput

Die in die Datei zu schreibenden Daten werden aus den bestehenden Daten und der neuen
Zeile neu zusammengestellt. Die Datei wird anschließend neu geschrieben. Zum Schluss wird
die Ausgabe in die Datei wieder geschlossen.
028
029
030
031
032
033
034
035
036
037

oOutputStream = createUnoService("com.sun.star.io.TextOutputStream")b = Split(stDataOld,"</" & stInstance & ">")
stDataNew = b(0) & stTmpData & CHR(13) & CHR(10) & "</" & stInstance & ">"oFileData = oFileAccess.OpenFileReadWrite(stFileData)oOutputStream.SetOutputStream(oFileData.getOutputStream)
oOutputStream.writeString(stDataNew)
oOutputStream.closeOutput()
END IF
END IF
END SUB

Wie hier nur am Beispiel des Umlesens der Daten gezeigt wurde kann so etwas natürlich auchzum Einlesen der Daten in eine Datenbank genutzt werden. Die Befüllung der Datenbank
würde dann über ein Formular erfolgen, von dem aus die Person, die die Daten schreibt, nicht
zwingend Zugriff auf die Daten hat, die bereits geschrieben wurden.

Formulareingabe optimieren
In der Standardeinstellung wird bei XML-Formulardokumenten immer die Seitenleiste mit den
Datenstrukturen des XML-Formulars (Daten-Navigator) und die Formular-Steuerelemente angezeigt. Die Symbolleiste für den Formular-Entwurf zeigt gegenüber Base-Formularen ein zusätzliches Symbol, mit der der Daten-Navigator ausgeschaltet werden kann:

Der Daten-Navigator kann dann nicht mehr über die Funktion zum Einblenden der Seitenleisteangezeigt werden. Wird dann zusätzlich noch die Symbolleiste für den Formularentwurf entfernt, so ist das Formular erst einmal gegen unbedachte Fehlnutzungen geschützt. Änderungen
an diesen Stellen bewirken keine Änderungen an dem Dokument und können daher nicht mit
dem Formular abgespeichert werden. Sie werden nur in den persönlichen Nutzereinstellungengespeichert. Wird allerdings die Datei über Datei → Eigenschaften → Sicherheit → Optionen fürFormulareingabe optimieren

17

Dateifreigabe → Schreibgeschützt öffnen beim Öffnen mit einem Schreibschutz versehen, so
wird das Formular nur zur Eingabe von Daten geöffnet.

Versandmethoden für den Formularinhalt4
In dem Reiter Vorlagen(Submissions) sind die Versandmöglichkeiten für den Formularinhalt
unter gebracht. Es stehen die für Internetformulare möglichen POST- und GET-Methoden sowie
die nur lokal gebräuchliche Methode PUT zur Verfügung. Die POST-Methode wird in dem Editor
allgemein als «Senden» bezeichnet.

POST-Methode
Hier wird der gesamte Inhalt als ein Element übertragen. Diese Methode findet Anwendung für
größere Formularinhalte oder auch für den Versand per Mail. Unter Aktion ist dann einzutragen:http://www.example.com/xmldata.php
mailto:lieschen.mueller@example.org
Der Mailversand läuft leider nicht ordnungsgemäß mit diesem Kommando ab, so dass er nur
mit Hilfe eines Makros und der PUT-Methode möglich ist.
Die Methode ruft mit dem Eintrag Submissions → Ersetzen → Dokument die ausführende Datei
mehrmals auf, dabei ab dem 2. Mal ohne Inhalt. Außerdem öffnet Writer z.B. die Datei «xmldata.php». Wird stattdessen der Eintrag Submissions → Ersetzen → Kein gewählt, so kann derInhalt anschließend durch das Script am Server einwandfrei verarbeitet werden.
Das Ersetzen erfolgt hier, wie bei allen anderen Methoden, nachdem der ursprüngliche Versand
erfolgt ist.
Der Empfang der gesandten Daten gestaltet sich etwas problematisch, da der Inhalt der xmlDatei verschickt wird. Die o.g. «xmldata.php» müsste dann mit dem folgenden Befehl auf die
Struktur der Datei zugreifen:
001
002
003
004

<?php
//Datei xmldata.php$datafile = file("php://input");?>

Der Inhalt sieht dann so aus:
001
002<?xml version="1.0" encoding="UTF-8"?><instanceData><Vorname>Lieschen</Vorname><Nachname>Müller</Nachname></instanceData>

Sollen die Daten gleich in eine XML-Datensammlung eingebunden werden, so erfolgt direkt inder PHP-Datei die Weiterverarbeitung:
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015

4

<?php
//Datei xmldata.php$datafile = file("php://input");$dataall = "data/Daten.xml";
IF (count($datafile) > 1) {$data = $datafile[1];$rootNode = substr($data, 1, strpos($data, ">")-1);$data = substr($data, strpos($data, ">")+1, strpos($data,"</".$rootNode.">")-strlen("<".$rootNode.">"));IF (file_exists($dataall)) {$datei_arr = file($dataall) ;array_pop($datei_arr);$datei_arr[] = $data."\r\n</".$rootNode.">";$datei = fopen($dataall, "w+");
foreach($datei_arr as $zeile){
fwrite($datei, $zeile);

Siehe hierzu das Beispiel «Formular_einfach.odt»

Versandmethoden für den Formularinhalt

18

016
017
018
019
020
021
022
023
024
025

}
fclose($datei);}?>}
ELSE {$datei = fopen($dataall, "a");fwrite($datei, $datafile[0]."<".$rootNode.">\r\n".$data."\r\n</".
$rootNode.">");}
fclose($datei);Zuerst wird der Inhalt über file in ein Array gelesen. Enthält das Array neben der ersten Zeile
Daten, so erfolgt eine Weiterverarbeitung. Der Dateninhalt des Arrays befindet sich in dem
2. Arrayelement, also $datafile[1], da die Zählung mit «0» beginnt. Die zu beschreibende
Datei «Daten.xml» liegt in dem obigen Beispielcode in einem Unterverzeichnis «data» (Zeile 4).
Die eigentlichen Daten liegen in der ankommenden Datei zwischen den Nodes für die Hauptinstanz (Wurzelelement, Zeile 8).
Existiert diese Datei nicht, so wird sie ab Zeile 19 mit dem Inhalt der abgesandten Datei, um
einige Zeilenumbrüche erweitert, abgespeichert. Die Zeilenumbrüche sind notwendig, damit
bei folgenden zusätzlichen Datensätzen der Abschluss der gemeinsamen Hauptinstanz (z. B.
</instanceData> ) jeweils einfacher ersetzt werden kann.
Existiert die Datei wird ab Zeile 9 in ein PHP-Array zeilenweise ausgelesen. Das letzte Element
des Arrays, das den Abschlusstag enthält, wird aus dem Array gelöscht (Zeile 11). Danach wird
der neue Datensatz sowie der Abschlusstag, mit einem Zeilenumbruch, an das Array angehängt (Zeile 12). Zum Schluss wird die Datei wieder komplett neu aufgebaut. Das Array wird
dabei Zeile für Zeile in die Datei übertragen.

GET-Methode
Diese Methode ist im Internet vor allem bei Suchmaschinen beliebt. Der gesamte Inhalt desFormulars wird über die URL in der Adressleiste des Browsers sichtbar weitergegeben. Dort
steht dann unter Aktion z.B.
http://www.example.com/xmldata_get.php?Vorname=Lieschen&Nachname=M%FCller
Mit der GET-Methode werden also lediglich die Daten direkt weiter gegeben. Allerdings passiertes, dass bei der GET-Methode die entsprechende Seite auf dem Webserver mehrmals mit Datenversorgt wird. Hier muss mit Hilfe des aufnehmenden Scripts und den entsprechenden Servervariablen gegengesteuert werden.
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020

<?php
//Datei xmldata_get.php$dataall = "data/Daten_einfach_formatiert.xml";
IF ($_SERVER['REQUEST_METHOD'] == "HEAD"){$vorname = $_GET["Vorname"];$nachname = $_GET["Nachname"];$data = "<Name><Vorname>".$vorname."</Vorname><Nachname>".
$nachname."</Nachname></Name>";IF (file_exists($dataall)) {$datei_arr = file($dataall) ;$rootNode = $datei_arr[count($datei_arr)-1];
array_pop($datei_arr);$datei_arr[] = $data."\r\n".$rootNode;$datei = fopen($dataall, "w+");
foreach($datei_arr as $zeile){
fwrite($datei, $zeile);}
fclose($datei);}}?>Versandmethoden für den Formularinhalt

19Die Daten werden hier in einer bereits auf dem Server liegenden Datei «Daten_einfach_formatiert.xml» abgespeichert. Das hat den Vorteil, dass dort auch direkt eine *.xsl-Datei eingebunden werden kann. Der Datei müssen also lediglich die Daten jeweils hinzugefügt werden.
Über die REQUEST_METHOD → HEAD wird dafür gesorgt, dass das Script nur einmal ausgeführt
wird. Hier wäre ab LO 7.6 auch die REQUEST_METHOD → GET möglich, die in vorhergehenden
Versionen leider für einen doppelten Versand verantwortlich war. Ab Zeile 5 werden die Variablen ausgelesen, die von dem Formular über die URL weiter gegeben wurden. Die Variablenbezeichnungen entsprechen den Elementsbezeichnungen in der Instanz. Die ermittelten Werte
werden anschließend zu einer Zeile als $data zusammengefasst.
Einträge in die vorliegende Datei werden nur ausgeführt, wenn die Datei bereits existiert(Zeile 8 ff.). In Zeile 10 wird die Abschlussbezeichnung für die Hauptinstanz (Wurzelelement)
ausgelesen, bevor sie anschließend aus dem Code entfernt wird. So kann die neue Zeile eingefügt und der Abschluss der Hauptinstanz nach einem Zeilenumbruch wieder angehängt werden. Wie beim POST-Befehl wird die Datei komplett neu Zeile für Zeile geschrieben.
Auch hier sollte, wie bei der POST-Methode, der Eintrag Submissions → Ersetzen → Kein gesetzt
werden.

PUT-Methode
Hier wird eine lokale Adresse eingetragen. Es wird eine Datei lokal geschrieben und abgelegt.

Vorsicht
Wird die Datei nicht rechtzeitig weiter verarbeitet, so wird der Inhalt mit einem erneuten Abschicken des Formulars überschrieben. Deswegen war diese Funktion zwischenzeitig völlig außer Kraft gesetzt und wird erst seit LO 7.6 mit einem Warn-Dialog wie
dem folgenden wieder aktiviert:

Als Aktion steht dort dann z.B.
file:///home/user/Dokumente/datendatei.xml
Auch unter Windows ist darauf zu achten, dass keine Backslashes verwandt werden 5. Dort alsoz.B.
file:///c:/tmp/datendatei.xml
Über ein Makro lässt sich diese Datendatei auch an eine Mail anhängen. Das Mailprogramm
wird dabei gestartet und das Absenden muss nur noch veranlasst werden:
001
002
003
004
005
006

5

SUB Mailversand
DIM attachs(0)IF GetGuiType() = 1 THEN
oMailer = createUnoService("com.sun.star.system.SimpleSystemMail")' Sonst Linux/Mac
ELSE

Als Hilfe zur Ermittlung der richtigen URL-Schreibweise dient die den Beispielen beigefügte Datei«URL_ermitteln.odt»

Versandmethoden für den Formularinhalt

20

007
008
009
010
011
012
013
014
015
016

oMailer = createUnoService("com.sun.star.system.SimpleCommandMail")
END IFoMailProgram = oMailer.querySimpleMailClient()oMessage = oMailProgram.createSimpleMailMessage()oMessage.setRecipient("lieschen.mueller@example.org")oMessage.setSubject("XML-Daten")
attachs(0) = "file:///home/user/Dokumente/datendatei.xml"
oMessage.setAttachement(attachs())
oMailProgram.sendSimpleMailMessage(oMessage, 0 )END SUB

Versand des gesamten Formulars per Mail
Natürlich kann nicht nur die Datendatei an eine Mail angehängt werden. Es ist auch möglich,das ganze Formular per Mail weiter zu versenden. 6 Ein Formular für so einen Mailversand
könnte so aussehen:

Die einfachste Methode hierzu ist im Writer der Weg über Datei → Senden → Dokument als EMail… . Komfortabler ist aber, solch ein Formular erst einmal auf die Vollständigkeit hin zu überprüfen, dann die Eingaben mit einem Schreibschutz zu versehen und anschließend zu versenden. Dadurch können nicht im Nachhinein versehentlich Daten zu dem Fortbildungsantrag verändert werden.
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025

6

SUB Submit_Mail
DIM oDoc AS OBJECTDIM oController AS OBJECTDIM oDrawpage AS OBJECTDIM oField AS OBJECTDIM oPath AS OBJECTDIM oMailer AS OBJECTDIM oMailProgram AS OBJECTDIM oMessage AS OBJECTDIM oUserData AS OBJECTDIM oUser AS OBJECTDIM oFileAccess AS OBJECT
DIM stTitle AS STRING
DIM stTimestamp AS STRING
DIM stPrintDir AS STRING
DIM stName AS STRING
DIM stMail AS STRING
DIM stUser AS STRING
DIM ar()oDoc = ThisComponent
oController = oDoc.getCurrentController()oDrawpage = oDoc.Drawpage
stTitle = oDoc.DocumentProperties.Title
REM Erforderliche Felder ueberprüfen
FOR i = 0 TO oDrawpage.Count - 1

Siehe hierzu das Beispiel «Fortbildungsantrag.odt»

Versandmethoden für den Formularinhalt

21

026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083

oField = oDrawpage.getByIndex(i).Control
IF oField.supportsService("com.sun.star.form.DataAwareControlModel") THEN
IF oField.Validator.RequiredExpression = "true()" ANDoField.Validator.getValue("string") = "" THEN
msgbox ("Die Einträge sind noch nicht vollständig." & CHR(13) &"Das Formular kann noch nicht versandt werden", 16, "Mailversand")
EXIT SUBEND IF
END IFNEXT
REM oDoc mit Timestamp abspeichern, sofern noch kein Timestamp enthalten
stTimestamp = Year(Now()) & "-" & Right("0" & Month(Now()),2) & "-" &Right("0" & Day(Now()),2) & "_" & Right("0" & Hour(Now()),2) & "-" &Right("0" & Minute(Now()),2)
oPath = createUnoService("com.sun.star.util.PathSettings")
stTempPath = oPath.Temp & "/LoFb"
REM vorher erstellte temporäre Dateien löschen, indem das Verzeichnis dafürgelöscht wird
oFileAccess = createUnoService("com.sun.star.ucb.SimpleFileAccess")
IF oFileAccess.exists(stTempPath) THEN
oFileAccess.kill(stTempPath)
END IFREM Speicherung direkt im gleichen Verzeichnis:
REM stDir = Left(oDoc.Location,Len(oDoc.Location)-Len(oDoc.Title))' Der Titel des Formulars wird von der URL abgetrennt.
IF Len(oDoc.Title) > 22 THEN
stPrintDir = stTempPath & oDoc.Title
ELSE
stPrintDir = stTempPath & "/" & stTitle & "_" & stTimestamp & ".odt"
END IFoDoc.StoreAsURL(stPrintDir,ar())
REM Ausgefüllte Felder mit Schreibschutz versehen, Namen auslesen
FOR i = 0 TO oDrawpage.Count - 1
oField = oDrawpage.getByIndex(i).Control
IF oField.supportsService("com.sun.star.form.DataAwareControlModel") THEN
IF oField.Validator.getValue("string") <> "" ANDoField.Validator.getValue("string") <> "0" THEN
oController.getControl(oField).Model.Enabled = False
END IF
IF oField.Name = "txt_Name" THEN
stName = oField.Text
END IF
IF oField.Name = "lbo_Mail" THEN
stMail = oField.CurrentValueEND IF
END IFNEXT
oDoc.Store()
REM Benutzerdaten für den Absender auslesen
DIM arUser(0) AS NEW com.sun.star.beans.PropertyValueoUserData = createUnoService("com.sun.star.configuration.ConfigurationProvider")arUser(0).Name = "nodepath"arUser(0).Value = "org.openoffice.UserProfile/Data"oUser = oUserData.createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", arUser())
stUser = oUser.givenname & " " & oUser.sn
REM Mail zusammenstellen und versenden
DIM attachs(0)IF GetGuiType() = 1 THEN
oMailer = createUnoService("com.sun.star.system.SimpleSystemMail")' Sonst Linux/Mac
ELSE
oMailer = createUnoService("com.sun.star.system.SimpleCommandMail")
END IFoMailProgram = oMailer.querySimpleMailClient()oMessage = oMailProgram.createSimpleMailMessage()

Versandmethoden für den Formularinhalt

22

084
085
086
087
088
089
090

oMessage.setRecipient(stMail)oMessage.setSubject("Fortbildungsantrag von " & stName)oMessage.Body = "In der Anlage finden Sie den ausgefüllten Fortbildungsantrag."& CHR(13) & CHR(13) & "Mit freundlichen Grüßen" & CHR(13) & CHR(13) & stUser
attachs(0) = stPrintDiroMessage.setAttachement(attachs())
oMailProgram.sendSimpleMailMessage(oMessage,0)
END SUB

Die Weiterleitung als Mailanhang erfolgt in 5 Schritten.
1. Die Felder werden darauf hin untersucht, ob auch alle notwendigen Felder ausgefüllt
worden sind. Hier werden die Eigenschaften des XML-Formulardokumentes
requiredExpression = "true()" abgefragt und geklärt, ob eventuell
getValue("string") bei einem erforderlichen Feld leer ist. Über diese Funktion können
alle Felder erreicht werden, während die Nachfrage nach oField.CurrentValue von den
benutzten Kontrollfeldern abhängig ist. (Zeilen 23 bis 31)
Ist ein erforderlicher Eintrag noch nicht vorhanden, so wird die Prozedur über EXIT SUB
nach Ausgabe einer Fehlermeldung direkt beendet. (Zeilen 27 und 28)
2. Das Formular wird im temporären Verzeichnis abgespeichert. Dabei wird dem vorgesehenen Namen, ermittelt aus Datei → Eigenschaften → Beschreibung → Titel, ein Zeitstempel hinzugefügt. (Zeilen 33 bis 48)
Wird das Formular mit dem entsprechenden Zeitstempel von der nächsten Person aufgerufen, so wird über die Länge des Dateinamens bestimmt, ob bereits ein Zeitstempel
enthalten ist. Dann wird einfach der aktuelle Dateiname beim Abspeichern übernommen(Zeile 47).
Alte Einträge im Temporären Verzeichnis werden mit Hilfe des zusätzlich erstellten
Unterverzeichnisses gelöscht. (Zeilen 37 bis 40)
3. Alle Felder, die bereits einen Inhalt haben, werden beim Export mit einem Schreibschutzversehen. Außerdem wird noch der Name der Person, für die der Antrag gestellt wird,
ausgelesen, damit dieser anschließend auch in den Betreff der Mail eingefügt werden
kann. (Zeilen 50 bis 65)
Diese Einstellungen werden nur in dem exportierten Formular geändert. Andernfalls
würde das Originalformular immer wieder nach einer Speicherung verlangen und die
Eingaben gesperrt werden. Deshalb muss erneut abgespeichert werden (Zeile 66).
4. Die Benutzerdaten aus Extras → Optionen → LibreOffice → Benutzerdaten werden für die
Erstellung des Mailinhaltes ausgelesen. (Zeilen 68 bis 73)
5. Die Mail wird entsprechend zusammengestellt und an das Mailprogramm weiter geleitet.
Die in Zeile 84 aufgeführte Mailadresse wurde aus einem Listenfeld in dem Formularausgelesen, dessen Liste direkt im Formularfeld gespeichert wurde:

Versandmethoden für den Formularinhalt

23

Komplexere Formulardefinition7
Das Einstiegsbeispiel hatte erst einmal nur zum Ziel, die prinzipielle Funktion eines XML-Formulars zu zeigen und dabei direkt aufkommende Probleme zu lösen. Jetzt soll es darum gehen,
XML-Formulare genauer zu durchschauen.
XML-Dateien starten mit der Nennung der XML-Version und der entsprechenden Kodierung fürdie Schriftzeichen, die verwendet werden. Der entsprechende Tag dazu nimmt immer die erste
Zeile der Datei ein.
Der gesamte weitere Inhalt wird durch Elemente strukturiert. Dabei werden für wohlgeformte
XML-Dateien folgende Punkte definiert8:•

Die XML hat genau ein Wurzelelement. Das äußere Element heißt in der Standardeinstellung des Formulareditors <instanceData>.

•

Alle Elemente haben einen Start- und einen Ende-Auszeichner. Im oberen Beispiel z.B.
<Vorname>Lieschen</Vorname>. Nur wenn die Elemente keinen Inhalt einrahmen
kann auch einfach ein Element mit abschließendem Bezeichner stehen:<ElementOhneInhalt />. Die Groß- und Kleinschreibung ist Teil der Bezeichnung.

•

Ein Element der gleichen Ebene muss geschlossen werden, bevor ein neues Element
geöffnet wird. Das Elternelement wird dann geschlossen, wenn alle Kindelementegeschlossen sind.

•

Einem Element können verschiedene Eigenschaftszuweisungen (Attribute) zugeordnet
werden. Allerdings dürften diese Attribute nicht gleiche Namen haben, da sonst die
Zuweisung unklar bleibt.

•

Den Attributen werden Attributeigenschaften zugeordnet, die in Anführungszeichen stehen müssen.

Definition der Instanzen
Jedes Modell hat genau eine Instanz. Zwar ist es möglich, mehrere Instanzen zu erstellen, nur
lässt sich leider keine richtige Bindung zu den Feldern der Instanzen erstellen, so dass auchkeine Dateneingabe in Felder dieser Instanzen bisher möglich ist. Werden mehrere Instanzen,z.B. für die Erstellung von Listenfeldern, benötigt, so muss über Modelle → Hinzufügen ein
neues Modell erstellt werden. In einem neuen Modell sind Instanzen, Übermittlungen (Submissions) und Bindungen neu. In einem Formular können mehrere Modelle existieren. Es kann vonModell zu Modell zum Bearbeiten umgeschaltet werden.

78

Siehe hierzu das Beispiel «Formular_komplex.odt»
Siehe: https://de.wikipedia.org/wiki/Extensible_Markup_Language

Komplexere Formulardefinition24Das obige Modell «LO_eV» hat eine Instanz «Mitglied». Standardmäßig ist das Root-Element«instanceData». Die Umbenennung des Root-Elements ist erst mit den LO-Versionen 7.4 undneuer möglich.

Tipp«instanceData» ist in LO-Versionen bis einschließlich LO 7.3 nicht änderbar. Eine Umbenennung ist bis LO 7.4 nur über das Einlesen einer XML-Datei möglich:
001
002
003

<?xml version="1.0" encoding="UTF-8"?><Mitglied></Mitglied>

Wird der obige Inhalt als einfache Textdatei abgespeichert und mit dem Namen«Start.xml» versehen abgespeichert, so kann über Instanzen → Bearbeiten der Link zu
dieser Datei eingelesen werden. «Mitglied» wird dann zum Startbegriff.
Nachdem «Mitglied» als Startbegriff erscheint sollte der Link wieder aus dem Dialog
entfernt werden. Der Button Instanz verknüpfen ist hier ohne Funktion. Ein Hinzufügen
von Elementen ist sonst nur scheinbar möglich und verschwindet beim nächsten Formularstart.

Dem Mitglied sind verschiedene Elemente baumartig untergeordnet. Enthalten Felder Werte, sosind diese über den Baum ersichtlich. Außerdem erscheinen die Werte auch im Formular selbst.
Werden den Feldern direkt auch über Element bearbeiten → Einstellungen → Datentyp Datentypen zugeordnet, so erstellt der Daten-Navigator automatisch die entsprechenden Bindungen,die für die Formularfelder nötig sind.

HinweisDatentypen können nur für Kindelemente, nicht aber für ein Elternelement eindeutig
festgelegt werden. So müsste beim Element «Person» der Datentyp leer bleiben, da die
Kindelemente «Vorname», «Nachname», «Geschlecht» und «Geburtsdatum» keinen einheitlichen Datentyp haben.

Komplexere Formulardefinition25

Bei den Modulen werden die Werte über Attribute, hier «selected» gespeichert. Im Daten-Navigator sind diese Werte nicht sichtbar. Die Bezeichnung mit «@» weist übrigens innerhalb von
XML darauf hin, dass es sich um ein Attribut des jeweiligen Elementes handelt. Der eigentlicheingegebene Name des Attributs wird ohne «@» geschrieben.

Für den Inhalt von Listenfeldern müssen die Werte in einem neuen Modell, hier «LO_Bundesland», erstellt werden. Dabei sind alle Elemente der 2. Stufe mit gleichem Namen benannt. So
Komplexere Formulardefinition

26

kann später über die Bindungen eine Liste aller Felder abgefragt werden. Die entsprechenden
Landesbezeichnungen über Element bearbeiten →Element → Standardwert eingetragen.

HinweisBei der Änderung von Eigenschaften bei den Instanzen oder auch anderen Elementen
kann es passieren, dass der Daten-Navigator die Änderungen in anderen Elementen
nicht aktualisiert. So macht sich z.B. eine Änderung bei den Eigenschaften eines Feldes
in den Instanzen erst nach dem Abspeichern, Schließen und erneutem Öffnen des Formulardokumentes auch bei den Bindungen bemerkbar.

Daten verschicken

Für die Buttons zur Weiterverarbeitung werden zwei Möglichkeiten erstellt:
1. Die Möglichkeit, die Daten direkt zu speichern, kombiniert eventuell mit dem weiteroben vorgestellten Makro, die Daten in einer zentralen XML-Datei weiter zu verarbeiten.
2. Die Möglichkeit, Daten an einen Server zu schicken. Dort wird die Datei in diesem Falle
mit einer *.php-Datei weiter verarbeitet.
Keine der Methoden dient dazu, nur einen Teil der Daten weiter zu bearbeiten. Dies ließe sichüber den Verweis (Bindungsausdruck) oder die Bindung zu einem Feld bewerkstelligen.
Als Bindungsausdruck könnte z.B. über «/Mitglied/Person» nur der Teil weitergegeben werden,
der unterhalb des Knotenpunktes «Person» abgespeichert ist.
Für die Bindung an ein Feld ist allerdings Vorsicht geboten, da die Auswahl einer Bindung durch
die GUI nicht mehr entfernt werden kann.

Komplexere Formulardefinition

27

Tipp
Manche Eigenschaften der GUI lassen darauf schließen, dass die Formularerstellungnoch nicht ganz ausgereift ist. Hier lässt sich nachsteuern, indem das Dokument
geschlossen wird und anschließend mit einem Packprogramm testweise eine Kopie entpackt wird.
In der entpackten «content.xml» lässt sich mit einem einfachen Texteditor jetzt z.B.
nach der fälschlicherweise erstellten Bindung suchen und dieser Eintrag löschen.
Anschließend wird diese «content.xml» wieder in die Kopie eingelesen. Funktioniert
alles wunschgemäß, so kann das Original durch die Kopie ersetzt werden.

Bindungen für Formularfelder
Die Bindungen für die Formularfelder werden dann automatisch erstellt, wenn bei Erstellen derElemente bereits ein Datentyp angegeben wurde. Ansonsten wird hier der gesamte Pfad ohne
das Wurzelelement, wie aus dem Screenshot ersichtlich, angegeben.

Bei der Bindungsbezeichnung muss darauf geachtet werden, dass die Bezeichnungen bei
unterschiedlichen Modellen nicht gleichen. Die Namensgebung funktioniert nämlich nur innerhalb eines Modells einwandfrei. Bindungen werden dort einfach durchnummeriert. Wird eine
Bindung gelöscht, so wird die Nummer anschließend wieder neu vergeben.

Komplexere Formulardefinition28

Hier wird die Bindung für das Listenfeld deutlich unterschiedlich zu den anderen Bindungen mit«Bindung_Land» benannt.

Formularfelder
Die Eigenschaften der Formularfelder unterscheiden sich deutlich von Formularfeldern z.B. in
Base. Beim Optionsfeld weist lediglich der Referenzwert den gleichen Charakter auf. Optionsfelder mit gleichem Namen zeigen auch hier die Eigenschaft, dass nur eine Option ausgewählt
werden kann. Hier sollte aber, wie bei Base-Formularen, besser im Reiter Allgemein der Gruppenname gleich gesetzt werden, da die Tabulatornavigation bei gleichen Feldnamen nicht korrekt verläuft.
Alle weiteren Daten-Eigenschaften entsprechen den Eigenschaften, die bereits vorher für das
entsprechende Feld eingestellt wurden. Zuerst wird das XML-Datenmodell «LO_eV» gewählt,dann aus diesem Modell die entsprechende Bindung. Dabei muss hier immer der Blick auf die
ausgeschriebenen Bindungen des Daten-Navigators gerichtet werden. Wer weiß schon auswendig, dass sich hinter «Bindung 9» das Feld «Adresse/PLZ» verbirgt?

Komplexere Formulardefinition

29

Die weiteren Einstellungen entsprechen dem der Elementdefinition.

Vorsicht
Die Eingaben unterhalb des Datentyps sind zwar ausgegraut. Sie lassen sich dennochauch für voreingestellte Datentypen nutzen. Dadurch werden die Datentypen für alle
entsprechenden Felder neu definiert.
Würde hier also z. B. für den Datentyp Zeichenfolge eine Länge von höchstens 10 Zeichen eingegeben, so würden alle Felder mit dem Datentyp Zeichenfolge maximal 10
Zeichen erlauben.

Hier ist allerdings das folgende Vorgehen zu beachten:•

Es sollte über Datentyp → Zeichenfolge → + … ein neuer Datentyp gewählt werden. Allefolgenden Einstellungen beziehen sich auf alle gleichlautenden Datentypen.

•

Für das Muster muss mit regulären Ausdrücken (siehe LO-Hilfe) gearbeitet werden.

Komplexere Formulardefinition

30

Ein neuer Datentyp wird erstellt, damit die Postleitzahl korrekt ist.

Die Elemente für den Datentyp «Zeichenkette PLZ» sind jetzt nicht mehr ausgegraut. Es ist
jetzt ein Muster eingestellt, das grundsätzlich nur Zahlen zulässt. Es sollen insgesamt 5 Zahlen
sein. Dies ist sowohl im Muster als auch im Längeneintrag eingestellt. Der Längeneintrag ist
dabei gar nicht mehr notwendig.
Der obige Eintrag ist erst seit LO 7.6 möglich. Vorher wurde das Feld auch als fehlerhaft angezeigt, wenn kein Eintrag gemacht wurde. Deshalb mussten Einträge mit einer Untergrenze von
0 festgesetzt werden: [:digit:]{0,5}.

Grundsätzlich führt diese Eingabe nur dazu, dass das entsprechende Feld mit einer roten
Umrandung und einer Fehlmeldung versehen wird. Wie bei allen anderen Datentypen kann die
Eingabe trotzdem abgespeichert und weiter geleitet werden.

Komplexere Formulardefinition

31

Für die Postleitzahl wurde die Zeichenfolge als Grundlage genommen. Beim Datentyp Dezimal
sind die Einstellungsmöglichkeiten entsprechend auf Zahleneingaben zugeschnitten.

Bei den Listenfeldern wird unter Daten → Listeneinträge aus das Modell mit der entsprechenden Bindung ausgesucht. Die jeweiligen Werte sind übrigens direkt unter Allgemein → Listeneinträge zu sehen. Das Listenfeld wird dann aber, wie die anderen Felder, an das XML-Datenmodell LO_eV gebunden.

Eingabebedingungen
Erforderlich
Dass eine Eingabe erforderlich sein soll lässt sich einfach unter Element Bearbeiten → Einstellungen → Erforderlich auswählen. Dann steht unter Bedingung «true()» und als Ergebnis «true»oder «false», je nachdem, ob die Bedingung erfüllt ist oder nicht.

Komplexere Formulardefinition32

Hier wird eine Bedingung für das Feld «/Mitglied/Beitrag/Bank/IBAN» oder auch «/Mitglied/Beitrag/Bank/BIC» formuliert. Ist über das Feld «/Mitglied/Beitrag/Bar» keine Wahl erfolgt (Wert: 0),
dann soll eine Eingabe erforderlich sein. Ansonsten hat sich die Eingabe in diesem Feld erledigt.
Im Ergebnis weist diese Bedingung gerade darauf hin, dass «Bar» bereits gewählt wurde.
Die Bedingung ist in diesem Fall direkt von dem ersten Element aus definiert, funktioniert abergenauso gut vom Element «Beitrag» aus, da ja das erste Element nur genau einmal vorkommen darf.

Relevant
Manchmal gibt es Datenfelder, deren Eintrag andere Datenfelder beeinflusst. In der Beispieldatenbank ist dies ein Feld, das angeklickt werden kann, wenn kein Adresseintrag erfolgen soll. In
den betreffenden Datenfeldern für Straße, Postleitzahl, Ort und Land werden die folgenden
Ergänzungen im Bereich Relevant (und gleichzeitig im Bereich Erforderlich) getätigt:

Komplexere Formulardefinition

33

Ist das Feld «Adresse» nicht angeklickt, dann sind die Felder «Strasse», «PLZ» usw. relevant.
Das Ergebnis ist true. Eine Eingabe kann erfolgen, ist sogar erforderlich, da gleichzeitig
Erforderlich mit der gleichen Bedingung gewählt wurde.

«keine Adresse angeben» ist nicht ausgewählt. Alle Felder für die Adresse erscheinen rot
umrandet, da jetzt überall eine Eingabe erforderlich ist.

Wird jetzt «keine Adresse angegeben» gewählt, so werden die Felder für die Adressangabe
deaktiviert. Sollen auch die Beschriftungen deaktiviert werden, so ist vorher bei den Formularfeldern die folgende Einstellung erforderlich:

In den Eigenschaften des Textfeldes, in diesem Beispiel des Formularfeldes für die Postleitzahl,
ist unter Allgemein → Beschriftungsfeld das Beschriftungsfeld angewählt worden. Nur wenndiese Verbindung klar ist kann auch das Beschriftungsfeld deaktiviert werden.

Einschränkung
Beim «Betrag» und bei der «Spende» ist eine Einschränkung hinzugefügt worden:

Komplexere Formulardefinition34

Es sollen schlicht nur Beträge erlaubt sein, die größer oder gleich 0 sind. Negative Zahlen werden also ausgeschlossen.

Schreibschutz und Berechnen
Für den Gesamtbetrag erfolgt eine Berechnung. Die Beträge sind hier in formatierbaren Feldern
erfasst. In Versionen vor LibreOffice 7.6 funktionierte zwar diese Berechnung, nur wurde das
Ergebnis nicht als Zahl korrekt ausgegeben. Dort war deshalb ein Textfeld statt eines formatierbaren Feldes für die Ausgabe notwendig.

Komplexere Formulardefinition

35

Die Berechnung erfolgt durch die Addition der Felder, die hier berücksichtigt werden sollen. Der
Editor versteht hier +, -, * und div (nicht: «/», da bereits anderweitig belegt) als Rechenanweisungen. Enthält das jeweilige Feld keinen Eintrag, so muss für die Ermittlung der Summe stattdessen eine «0» angenommen werden. Sonst wird bei der Ergebnisermittlung NaN (not a number) ausgegeben.

In den Dateneigenschaften des Textfeldes wird dann auch diese entsprechende Berechnunganschließend sichtbar. Die Dateneigenschaften werden hier beständig aktualisiert, wenn eineÄnderung in den Bedingungen der Einstellungen des Elements erfolgt.

Komplexere Formulardefinition

36

Neben den einfachen Berechnungen stehen auch einige Funktionen zur Verfügung. Hier wurde
mit der Funktion now() der aktuelle Tag und die aktuelle Zeit wieder gegeben.

Formatierte Ausgabe in XML-Dokumenten
Prinzipiell können die Daten, wie oben beschrieben, über ein Makro oder über den Server einer
gemeinsamen XML-Datei zugeführt werden. Für die einfache formatierte Ausgabe wurde eine
entsprechende XSL-Datei bereits vorgestellt. Bei dem jetzt anfallenden Datenanteil ist natürlicheine einfache Tabellenzeile nicht mehr ausreichend für die Daten. Hier nur ein Ausschnitt derneuen XSL-Datei, die zeigt sich auf die letzten beiden Tabellenzeilen der Darstellung im Browser konzentriert und zusätzliche Funktionen birgt:
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021

<tr>
<th></th><th>Betrag</th><th>Spende</th><th>Gesamt</th><th>Bar</th><th>IBAN</th><th>BIC</th>
</tr>
<tr>
<td></td><td><xsl:value-of select="Beitrag/Betrag"/></td><td><xsl:value-of select="Beitrag/Spende"/></td><td><xsl:value-of select="Beitrag/Gesamtbetrag"/></td><td><xsl:if test="Beitrag/Bar=1">Ja</xsl:if><xsl:if test="Beitrag/Bar=0">Nein</xsl:if></td><td><xsl:if test="Beitrag/Bank/IBAN=''"> -</xsl:if><xsl:value-of select="Beitrag/Bank/IBAN"/></td><td><xsl:if test="Beitrag/Bank/BIC=''"> -</xsl:if><xsl:value-of select="Beitrag/Bank/BIC"/></td></tr>

Die Tabellenheader werden jetzt mitgeführt, so dass jedes einzelne Element auch seine
Bezeichnung hat. Die Schriftart wird in den Formatierungsanweisungen für die Header verkleinert.
Wenn im Feld «Bar» eine '1' steht, dann wird 'Ja' ausgegeben, bei '0' 'Nein'. Für die IBAN bzw.
BIC wird bei leeren Feldern ein ' -' eingefügt.
001

<tr>

Komplexere Formulardefinition

37

002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017

<th></th><th colspan="5">Module</th><th>Antragszeitstempel</th>
</tr>
<tr>
<td></td><td colspan="5"><xsl:if test="Modul/Base/@selected='true'">Base </xsl:if><xsl:if test="Modul/Calc/@selected='true'">Calc </xsl:if><xsl:if test="Modul/Draw/@selected='true'">Draw </xsl:if><xsl:if test="Modul/Impress/@selected='true'">Impress </xsl:if><xsl:if test="Modul/Writer/@selected='true'">Writer </xsl:if><xsl:if test="Modul/Dokumentation/@selected='true'">Dokumentation </xsl:if></td><td><xsl:value-of select="Antrag/Datum_Zeit"/></td></tr>

Die Module werden in einer Tabellenspalte zusammengefasst und so geschrieben, dass zwischen den Modulen jeweils ein Leerzeichen auftaucht. Die Eigenschaft des Attributes wird
hierzu ausgelesen.

XML-Formulare mit Datenbankanbindung nutzen9XML-Formulare speichern erst einmal nur den aktuellen Formularinhalt und geben diesen auchals xml-Datei weiter. Sie lassen sich nicht zum Navigieren durch vorherige Datenbankinhaltenutzen.
Mit Base besteht die Möglichkeit, Datensätze auszulesen und diese dann in den XML-Formularen darzustellen, zu verändern und neue Daten hinzuzufügen. Hierzu ist allerdings der Einsatz
von Makros unabdingbar.
Vorteil dieser Konstruktion ist, dass Formulare so gestaltet werden können, dass dem Nutzer
der Datenbankunterbau im Detail verborgen bleibt. Das Formular selbst weist hier die Datenbankverbindung nicht aus. Sie wird über Makros zur Verfügung gestellt.

Makrozugriff über die Bindungen des XML-Formulars
Der Kontakt zu den Datenfeldern des XML-Formulars erfolgt über die Bindungen des Formulars.
Dazu werden zuerst einmal die Bezeichner für die Bindungen von den standardmäßigen «Bindung 1» usw. umbenannt in Bezeichner, die genau die gleiche Bezeichnung wie die Datenfelder
haben:

9

Siehe hierzu das Beispiel «Formular_komplex_Base.odt» sowie die Datenbank «XML_Daten.odb»

XML-Formulare mit Datenbankanbindung nutzen

38Die Bindungen haben jetzt Bezeichner wie «Betrag», «Bar» usw. Über den folgenden Code können jetzt einzelne Datenfelder und die dazugehörigen Formularfelder mit Inhalten versehen
werden.
001
002

oBinding = thisComponent.XForms.getByName("LO_eV").Bindings
oBinding.getByName("Vorname").setValue("Otto")

Das Writer-Dokument («thisComponent») bietet den Kontakt zu den Bindungen an. Die einzelne
Bindung wird mit dem Namen ausgewählt und der Wert in die Bindung geschrieben. Der Wert
erscheint dann direkt in den Elementen und in den Formularfeldern.
Mit dieser Methode lässt sich auch ein Formular zurücksetzen, so dass dort keine Werte mehr
stehen. XML-Formulare bieten diese Möglichkeit sonst nicht. Allerdings fehlt den Formularfelder
in XML-Formularen eine Eigenschaft, die Formularfelder mit Datenbankanbindung haben: Sielassen sich nicht über die GUI auf NULL setzen. Dadurch wird bei einem leeren Text in Datumsfeldern stattdessen '01.01.1990' ausgegeben. Bei numerischen Feldern erscheint, abhängig
von der Formatierung, z.B. '0,00 €'. Das ist nicht nur lästig, wenn z.B. zuerst das Defaultdatum
gelöscht wird. Es führt auch leicht dazu, dass das Defaultdatum direkt mit abgespeichert wird.
Um Datumsfelder auf leere Felder setzen zu können muss auf den Controller zugegriffen werden:
001
002
003
004
005

oForm = ThisComponent.Drawpage.Forms.getByIndex(0)oController = ThisComponent.getCurrentController()oFieldGeburtsdatum = oForm.getByName("datGeburtsdatum")oViewGeb = oController.getControl(oFieldGeburtsdatum)oViewGeb.setEmpty

Bei numerischen Feldern gibt es die Methode setEmpty nicht. Hier werden die Felder mit
setText zurückgesetzt:
001
002
003

oFieldBetrag = oForm.getByName("numBetrag")oViewBet = oController.getControl(oFieldBetrag)oViewBet.setText("")

Jetzt kann das Formular mit Daten gefüllt und für die Eingabe von neuen Daten zurückgesetzt
werden.

XML-Formulare mit Datenbankanbindung nutzen

39Base-Tabellen erstellen
Für die Datenbank werden 2 Tabellen und eine Ansicht erstellt:

Die Tabelle "Mitglied" enthält alle Daten, die abgespeichert werden sollen. Zusätzlich zu den
ursprünglich im XML-Formular enthaltenen Feldern wird ein Feld "ID" für die Speicherung desautomatisch erstellten Primärschlüssels erstellt. Dieses Feld muss auch in das XML-Formular als
Element übernommen werden, braucht aber nicht als Formularfeld zu erscheinen.
Die Tabelle "Filter" wird dazu benutzt, über das Formular die Datensätze nach bestimmten"Nachnamen" zu durchsuchen. Deshalb enthält diese Tabelle lediglich ein Feld "ID" als Ja/NeinFeld, das gleichzeitig der Primärschlüssel ist, und ein Feld "Nachname". Die Tabelle besteht
grundsätzlich nur aus einem Datensatz, der immer wieder überschrieben wird.
In der Ansicht "Fil_Mitglied" sind alle Datensätze aufgeführt, die der Filterung aus der Tabelle"Filter" entsprechen:
001 SELECT * FROM "Mitglied" WHERE
002
IFNULL( LOWER ( "Nachname" ), '' ) LIKE '%' ||003
IFNULL( ( SELECT LOWER ( "Nachname" ) FROM "Filter"
WHERE "ID" = TRUE ), '' ) || '%'Aus der Tabelle "Filter" wird der "Nachname" für den Datensatz ausgelesen, bei dem "ID" auf
Wahr (TRUE) gesetzt ist. Die Eingabe wird in Kleinbuchstaben umgewandelt, damit der Vergleich
nicht an den Unterschieden zwischen Groß- und Kleinschreibweise scheitert. Der ausgelesen
Inhalt wird mit dem Inhalt des Feldes "Nachname", ebenfalls in Kleinschreibweise umgewandelt, über die Funktion LIKE verglichen. Die Position des Filterwertes ist dabei so gesetzt, dassbeliebig viele Zeichen vor und nach dem Filterwert vorkommen können. So gibt die Abfrage alle
Datensätze wieder, bei denen z.B. der "Nachname" an irgendeiner Stelle den Buchstaben 'k'enthält, wenn dieser als Filterwert eingeben wurde.
Damit die Möglichkeit besteht, auch alle Datensätze über den Filter anzeigen zu können, muss
bei einer leeren Eingabe nachgeholfen werden. Die leere Eingabe wird über IFNULL mit einem
leeren Text ersetzt. Gleiches gilt auch für eventuell leer gebliebene Eingaben in das Feld "Nachname" in der Tabelle "Mitglied". Diese Datensätze würden sonst nicht mehr auftauchen. 10

Makrozugriff auf die Base-Datenbank
Der Zugriff zu Datenbanken ist im Detail im Base-Handbuch beschrieben. Hier deshalb nur
einige Kommentare zu wichtigen Details.
Die erste Prozedur «DatenTabelle_Start» muss beim Öffnen des Formulars direkt gestartet werden. Sie wird deshalb über Extras → Anpassen → Ereignisse → Ansicht wurde erzeugt in das
Formular eingebunden.
001
002
003
004
005
006
007
008

SUB DatenTabelle_StartoXForm = ThisComponent
stDir = Left(oXForm.Location,Len(oXForm.Location)-Len(oXForm.Title))
stDir = ConvertToUrl(stDir & "XML_Daten.odb")
oDatabaseContext = createUnoService("com.sun.star.sdb.DatabaseContext")
oDatasource = oDatabaseContext.getByName(stDir)
oConnection = oDatasource.GetConnection("","")
oStatement = oConnection.createStatement()

10 Siehe dazu im Detail das Base-Handbuch, besonders die Kapitel Abfragen und Datenfilterung

XML-Formulare mit Datenbankanbindung nutzen

40

009

oStatement.ResultSetType = com.sun.star.sdbc.ResultSetType.SCROLL_SENSITIVE

Der ResultSetType muss zum freien Scrollen freigeschaltet werden. Ansonsten kann nur vorwärts durch die Datensätze gescrollt werden. Deswegen hier der Zusatz SCROLL_SENSITIVE. So
könnten auch Datenänderungen in den bestehenden Datensätzen nachvollzogen werden. Mit
der internen HSQLDB ist es allerdings nicht möglich, dem ResultSet auch neue Daten hinzuzufügen. Daher kann hier ohne Probleme auf die nicht beschreibbare Ansicht "Fil_Mitglied"zugegriffen werden. Für Datenänderungen wird später auf den direkten SQL-Code zurückgegriffen.
010
011
012
013
014
015
016

stQuery = "SELECT ""ID"", ""Vorname"", ... , ""Datum_Zeit""
FROM ""Fil_Mitglied"""oResult = oStatement.executeQuery(stQuery)
IF oResult.last THEN
stLast = oResult.getRow
ELSE
stLast = "0"
END IFDie Abfrage ist hier nur verkürzt dargestellt. Sie umfasst alle Felder der Tabelle und könnte
auch über
010

SELECT * FROM "Fil_Mitglied"erstellt werden. Da im Code aber der Bezug zu den einzelnen Feldern klarer sein sollte wird hierjedes Feld einzeln benannt.
Nach dem Erstellen des Ergebnisobjektes oResult wird zuerst zum letzten Datensatz gescrollt
und dort die Nummer des Datensatzes über getRow abgefragt. Anschließend wird wieder zum
ersten Datensatz gescrollt und die Prozedur WerteInFormular aufgerufen, die die Werte ausder Datenbank in das Formular überträgt. Ist noch kein Datensatz vorhanden, so wird stattdessen das Formular zurückgesetzt.
017
018
019
020
021
022
023

IF oResult.first THEN
stPosition = oResult.getRow
WerteInFormular
ELSE
stPosition = "0"
WerteInFormularResetEND IF

Um das Filterfeld in dem Formular noch mit dem entsprechenden Inhalt zu versorgen wird auchnoch die Tabelle "Filter" kurz abgefragt. Der Inhalt wird direkt dem Filterfeld zugewiesen. Das
Filterfeld ist ansonsten nicht Element des XML-Formulars.
024
025
026
027
028
029
030
031

oStatementF = oConnection.createStatement()
stSql = "SELECT ""Nachname"" FROM ""Filter"" WHERE ""ID"" = TRUE"
oResultF = oStatementF.executeQuery(stSql)
oResultF.Next
stFilter = oResultF.getString(1)ThisComponent.Drawpage.Forms.getByIndex(0).
getByName("Textfeld_Filter_Nachname").Text = stFilter
END SUB

Für die Navigation müssen einige Variablen dieser Prozedur auch außerhalb der Prozedur weiterverfügbar sein. Sie werden zu Beginn des Moduls notiert. Sobald allerdings über Extras →Makros → Makros bearbeiten der Makroeditor geöffnet wird, sind die in den globalen Variablen
gespeicherten Inhalte gelöscht. Das führt dann dazu, dass das Scrollen durch die Datenbank
nicht mehr möglich ist und das Formular stattdessen neu gestartet werden muss.
001
002
003
004
005

GLOBAL oConnection AS OBJECTGLOBAL oStatement AS OBJECTGLOBAL oResult AS OBJECTGLOBAL stLast AS STRING
GLOBAL stPosition AS STRING

Die Navigationsleiste im Formular soll so aussehen:

XML-Formulare mit Datenbankanbindung nutzen

41

Der Wert für stPosition ist in der Abbildung '1', der Wert für stLast '4'. Jetzt sind Navigationsbuttons mit Prozeduren zu verbinden.
Mit oResult.First wird der erste Datensatz angesprungen und die entsprechenden Werte fürdiesen Datensatz werden über WerteInFormular in das Formular eingelesen.
001
002
003
004
005
006
007
008

SUB ErsterDatensatz
IF oResult.First THEN
stPosition = oResult.getRow
ELSE
stPosition = "0"
END IF
WerteInFormular
END SUB

Das Scrollen zum vorhergehenden Datensatz ist etwas komplizierter, da nicht vor den ersten
Datensatz gesprungen werden soll. Dies wird in der ersten Bedingung abgefangen. Die zweite
Bedingung klärt den Fall, dass vorher ein neuer Datensatz angesprungen wurde und die Position des neuen Datensatzes größer war als die des letzten existierenden Datensatzes. Unterdieser Bedingung soll zum vorher letzten Datensatz gesprungen werden. Ansonsten ist einfachüber oResult.previous der Sprung zum vorherigen Datensatz mit Abfrage der Position möglich.
001
002
003
004
005
006
007
008
009
010
011
012

SUB VorherigerDatensatz
IF oResult.isFirst THEN
stPosition = oResult.getRow
ELSEIF stPosition > stLast THEN
oResult.absolute(stLast)
stPosition = stLastELSE
oResult.previous
stPosition = oResult.getRow
END IF
WerteInFormular
END SUB

Zum nächsten Datensatz geht es mit oResult.next. Ist bereits der letzte Datensatz erreicht,
so wird die Position um eine Position höher als der eigentlichen Position angesetzt. Das Formular wird außerdem über WerteInFormularReset von allen Inhalten geleert. Ähnlich wird auchbeim letzten Datensatz verfahren.
001
002
003
004
005
006
007
008
009
010

SUB NaechsterDatensatz
IF oResult.isLast THEN
stPosition = oResult.getRow + 1
WerteInFormularReset
ELSE
oResult.next
stPosition = oResult.getRow
WerteInFormular
END IF
END SUB

001
002
003
004
005
006
007
008
009
010

SUB LetzterDatensatz
IF oResult.isLast THEN
stPosition = oResult.getRow + 1
WerteInFormularReset
ELSE
oResult.Last
stPosition = oResult.getRow
WerteInFormular
END IF
END SUB

XML-Formulare mit Datenbankanbindung nutzen

42Der neue Datensatz wird über den letzten Datensatz erreicht. Anschließend wird einfach die
Position so angezeigt, dass z.B. '4' von '3' Datensätzen angezeigt würden. Das Formular wird
wieder geleert.
001
002
003
004
005

SUB NeuerDatensatz
oResult.Last
stPosition = oResult.getRow + 1
WerteInFormularResetEND SUB

Für das Speichern werden die Felder über die Bindungen ausgelesen. Dabei muss der Datentyp
für die Funktion getValue() angegeben werden. Hier wird grundsätzlich der Datentyp"string" gewählt.
001
002
003
004

oBinding = thisComponent.XForms.getByName("LO_eV").Bindings
stID = oBinding.getByName("ID").getValue("string")
stVorname = String_to_SQL(oBinding.getByName("Vorname").getValue("string"))...

Existiert bereits ein Eintrag für das Feld «ID», so handelt es sich um einen bereits existierenden
Datensatz. Folglich muss über SQL ein Update erfolgen. Andernfalls handelt es sich um einen
neuen Datensatz. Der SQL-Befehl hierfür ist der Insert-Befehl. Nur bei einem neuen Datensatz
muss anschließend die Tabelle neu eingelesen werden, damit das Scrollen durch die Datensätze
wieder klappt. Außerdem wird dann direkt zum letzten Datensatz navigiert.
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021

IF stID <> "" THEN
'UpdatestSql = "UPDATE ""Mitglied"" SET ""Vorname"" = "+stVorname+",""Nachname"" = "+stNachname+"," ...
stSql = stSql + " WHERE ""ID"" = "+stID+""oStatement1 = oConnection.createStatement()
oStatement1.executeUpdate(stSql)
ELSE'InsertstSql = "INSERT INTO ""Mitglied"" (""Vorname"",""Nachname""," ... ")"stSql = stSql + " VALUES ("+stVorname+","+stNachname+"," ... ")"oStatement1 = oConnection.createStatement()
oStatement1.executeUpdate(stSql)
DatenTabelle_StartoResult.Last
stPosition = oResult.getRow
WerteInFormular
END IFDie Werte in dem XML-Formular werden als String ausgelesen. Dabei sollen nacheinander folgende Änderungen in den Strings vorgenommen werden, damit sie von der Datenbank einwandfrei verarbeitet werden können:
1. Hochkommata (') werden in SQL als Textbegrenzer eingesetzt. Kommen diese Hochkommata allerdings innerhalb eines Textes vor, so müssen sie mit einem weiteren Hochkomma maskiert werden.
2. Ist der String leer, so soll an die Datenbank kein leerer String ('') weitergegeben werden.
Stattdessen wird NULL, also «keine Daten», an die Datenbank gesandt.
3. Besteht der String aus der Zahl 1 oder 0, so ist dies ohne Hochkommata weiter zu
geben. Ansonsten wird es als Text betrachtet und vor allem nicht für Ja/Nein-Felder als
Alternative zu True/False angesehen.
4. Trifft weder Punkt 2 noch Punkt 3 zu, so handelt es sich um einen Ausdruck, der problemlos in Hochkommata eingeschlossen weitergegeben werden kann.
001
002
003
004
005
006
007

FUNCTION String_to_SQL(st AS STRING)IF InStr(st,"'") THEN
st = Join(Split(st,"'"),"''")END IFIF st = "" THEN
st = "NULL"ELSEIF st = "1" OR st = "0" THEN

XML-Formulare mit Datenbankanbindung nutzen

43

008
009
010
011
012
013

st = stELSE
st = "'" & st & "'"END IF
String_to_SQL = stEND FUNCTIONIn XML-Formularen hat die Angabe eines Zeitstempels das Format '2018-03-28T19:30:27Z'. Fürdie Weitergabe in SQL muss das 'T' durch eine Leerstelle ersetzt werden. Das 'Z' muss von dem
Zeitstempel abgetrennt werden, so dass schließlich '2018-03-28 19:30:27' abgespeichert werden kann.
001
002
003
004
005

FUNCTION XMLTime_to_SQLTime(st AS STRING)
st = Join(Split(st,"T")," ")st = Join(Split(st,"Z"),"")
XMLTime_to_SQLTime = stEND FUNCTION

Für die Datenfilterung ist der Name des Textfeldes in den Zusatzinformationen des Buttons(Tag) abgespeichert. Hier wird er ausgelesen und darüber dann der Inhalt des Textfeldes
bestimmt. Die Tabelle "Filter" erhält ein Update und anschließend wird die Datentabelle neu
eingelesen.
001
002
003
004
005
006
007
008

SUB Filtern(oEvent AS OBJECT)
oButton = oEvent.Source.Model
stFilter = oButton.Parent.getByName(oButton.Tag).Text
stSql = "UPDATE ""Filter"" SET ""Nachname"" = '"+stFilter+"'
WHERE ""ID"" = TRUE"
oStatementF = oConnection.createStatement()
oStatementF.executeUpdate(stSql)
DatenTabelle_Start
END SUB

Hiermit lässt sich jetzt durch einen Datenbank scrollen, ein Datensatz bearbeiten und ein neuer
Datensatze eingeben. Auch die Suche in vorhandenen Datensätzen ist möglich.

Abgespeicherte XML-Dateien einlesen11
Werden über das Formular Daten als XML-Datei abgespeichert, so kann es zur Auswertung auf
einem anderen Rechner auch sinnvoll sein, die Daten wieder einlesen zu können. Gegebenenfalls können so Daten aus vielen Formularen z.B. in eine Datenbank über das Formular eingelesen, mit anderen Daten zusammengeführt und wieder abgespeichert werden.
Eine abgespeicherte XML-Datei hat z.B. folgenden Inhalt:
001
002<?xml version="1.0" encoding="UTF-8"?><Mitglied><Person><Vorname>Lara</Vorname><Nachname>Schmidtke</Nachname><Geschlecht>w</Geschlecht><Geburtsdatum>2018-01-01</Geburtsdatum></
Person><Adresse>1</Adresse><Kontakt><Telefon>08754890123</
Telefon><EMail>lara64@example.com</EMail></Kontakt><Beitrag><Bar>1</
Bar><Betrag>0</Betrag><Spende>10</Spende><Gesamtbetrag>10</
Gesamtbetrag><Bank><IBAN/><BIC/></Bank></Beitrag><Modul><Baseselected="false"/><Calc selected="false"/><Draw selected="true"/><Impress
selected="false"/><Writer selected="false"/><Dokumentation
selected="false"/></Modul><Antrag><Datum_Zeit>2018-03-27T16:47:44Z</Datum_Zeit></
Antrag></Mitglied>

Die Daten dieser Datei sollen jetzt in das Formular übertragen werden. Wie beim Kopieren derneuen Daten in eine dauerhafte Datendatei wird hier zuerst der Inhalt der XML-Datei eingelesen.
001
002
003
004

SUB ImportoDoc = ThisComponent
stDir = Left(oDoc.Location,Len(oDoc.Location)-Len(oDoc.Title))
stFile = stDir & "Beispiel_4.xml"

11 Siehe hierzu das Beispiel «Formular_komplex_Base_Import.odt»

Abgespeicherte XML-Dateien einlesen

44

005
006
007
008
009
010
011
012
013

oFileAccess = createUnoService("com.sun.star.ucb.SimpleFileAccess")
IF oFileAccess.exists(stFile) THEN
oInputStream = createUnoService("com.sun.star.io.TextInputStream")oFile = oFileAccess.OpenFileReadWrite(stFile)oInputStream.SetInputStream(oFile.getInputStream)
DO WHILE NOT oInputStream.isEOF
stTmp = stTmp & oInputStream.ReadLine()
LOOP
oInputStream.closeInput

Nach dem Einlesen wird zuerst der einführende Inhalt der XML-Datei von den eigentlichen
Daten getrennt. Trennsymbol ist hier ?>.
014

a = Split(stTmp,"?>")

Die nachfolgenden Felder haben den folgenden Aufbau:
001<Mitglied><Person><Vorname>Lara</Vorname><Nachname>Schmidtke</Nachname><Geschlecht>w</Geschlecht><Geburtsdatum>2018-01-01</Geburtsdatum></
Person><Adresse>1</Adresse> ...

Wird jetzt nach >< getrennt, so bleibt das Element und der Inhalt des Elementes grundsätzlich
zusammen bestehen:015

aTmpData = split(a(1),"><")

Dies führt zu folgender Trennung:
001
002
003
004
005
006
007
008
009

<Mitglied
PersonVorname>Lara</Vorname
Nachname>Schmidtke</Nachname
Geschlecht>w</Geschlecht>
...
Modul
Base selected="false"/>...

Aus diesem Array müssen jetzt die Elemente (oder aus Datenbanksicht die Feldbezeichnungen)sowie die Inhalte, die zu dem jeweiligen Element gehören, extrahiert werden. Nur Arrayelemente mit </ und = (siehe die Auswahlelemente aus den Modulen) müssen weiter bearbeitet
und in das Formular übernommen werden. Sie werden nach den jeweils entsprechenden Kriterien wieder in Elemente (Feldbezeichnungen) und Daten aufgesplittet.
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035

k = 0
FOR i = 0 TO UBound(aTmpData)
IF InStr(aTmpData(i),"</") OR InStr(aTmpData(i),"=") THEN
REDIM PRESERVE aField(k)REDIM PRESERVE aData(k)IF InStr(aTmpData(i),"</") THENb = split(aTmpData(i),">")
c = split(b(1),"</")
aField(k) = b(0)aData(k) = c(0)END IFIF Instr(aTmpData(i),"=") THENb = split(aTmpData(i)," ")c = split(b(1),"""")
aField(k) = b(0)aData(k) = c(1)END IFk = k+1
END IF
NEXT iAnschließend wird das gesamte Formular, wie bei der Eingabe neuer Daten, erst einmal vonallem Inhalt geleert. Dann wird die Verbindung zu den Bindungen des XML-Formulars aufgenommen und die Daten der jeweiligen Bindung zugeschrieben.
036
037

WerteInFormularResetoBinding = oDoc.XForms.getByName("LO_eV").Bindings

Abgespeicherte XML-Dateien einlesen

45

038
039
040
041
042

FOR i = 0 TO UBound(aField)
oBinding.getByName(aField(i)).setValue(aData(i))
NEXT iEND IF
END SUB

Das Makro funktioniert, ähnlich wie die Makros zu Datenbankanbindung, natürlich nur dann einwandfrei, wenn die Bindungen die gleichen Bezeichnungen haben wir die entsprechenden Elemente.

AnhangSubmissions-Methoden12
MethodSerialization

Schemespostxml

http(s) mailto

put

xml

http(s) filegeturl encoded

http(s) fileurlencoded-post

url encoded

http(s) mailto

form-data-post

multipart form data

http(s) mailto

multipart-post

multipart related

http(s) mailto

Xforms Funktionen13
FunctionArguments

Returns

Description

avg

node-set

numberAverageboolean-from-string

stringbooleanType conversion

count-non-empty

node-set

numberCount non-empty

days-from-datestringnumberDays in epoch

ifboolean, string, string

stringConditionalindex

stringnumberRepeat index

instance

stringnode-set

Locate instancemax

node-set

numberMaximumminnode-set

number

MinimummonthsstringnumberMonths in period

now-

stringCurrent time

property

stringstringFeature value

seconds

stringnumberSeconds in period

seconds-from-dateTime

stringnumberSeconds in epoch

XPath Operators
|

Union

*

Wildcard[]

Predicate+ - * div mod

Arithmetic= < <= > >= != and or

Boolean

12 Siehe https://www.w3.org/MarkUp/Forms/2006/xforms-qr
13 Siehe https://www.w3.org/MarkUp/Forms/2006/xforms-qr

Anhang46

Datentypen
Englische
Bezeichnung

DeutscheÜbersetzung

UmfangAnsicht im
Textfeld

Bevorzugtes Formularfeld

Date

Datum

Datum, auchführende Nullen

2023-05-31

31.05.23(Datumsfeld)

Date and Time

Datum und Zeit

Datum und Zeit,
auch führende
Nullen2023-0531T10:25:00

31.05.23 10:25(Formatiertes Feld)

Day

Tag

1 bis 31, auchführende Nullen

31

31(Formatiertes Feld,
auf 2 Stellen eingestellt)

DecimalDezimalunbegrenzt

2.35

2,35
(Formatiertes Feld,hier können auch
Maßeinheiten wie«€» hinzugefügt
werden)Double precision

Doppelte
Genauigkeit

Wie Dezimal

2.356789

2,356789(Formatiertes Feld)

Floating point

Fließkomma

Wie Dezimal

2.356789

2,356789(Formatiertes Feld)

Hyperlink

Hyperlink

Start mit http,https, ftp …

http://libreoffice.org

http://libreoffice.org(Textfeld)

Month

Monat

1 bis 12, auchführende Nullen

5 oder 05

05(Formatiertes Feld,
auf 2 Stellen eingestellt)

StringZeichenfolge

beliebigbeliebig (Textfeld)

Time

Zeit

00:00 bis 24:00

10:25:00

10:25 oder andere
Formate(Formatiertes Feld)

True/False (Boolean)

Wahr/Falsch(Boolean)

1 oder 0

1✓(Markierfeld)

Year

Jahr

2023, auch führende Nullen

2023

2023
(Formatiertes Feld)

Das Formatierte Feld ist hier das Allroundfeld. Es lässt auch Zeiten wie 24:00:00 zu,
beschränkt Zahlen nötigenfalls auf 2 Zeichen (Tag, Monat), kann Maßeinheiten wie den «€» hinzufügen usw. Lediglich beim Datum hat das Datumsfeld den Vorteil, dass es sich aufklappbar
schalten lässt. Beim Wahr/Falsch-Feld ist dann das Markierfeld durch die Anklickbox besser
geeignet.
Das Textfeld sollte nur für Texteingaben wie eine Zeichenfolge oder den Hyperlink genutzt werden. Lediglich die Eingabe von Zeiten ist noch von der Zeichennutzung her für deutschsprachige NutzerInnen einfach um zu setzen. Datumseingaben und Kombinationen von Datum und
Zeit sind gewöhnungsbedürftig. Auch die Eingabe des Dezimaltrenners in Form eines Punktesdürfte häufig zu Fehlern führen.

Anhang47

Anhang48