Abstract: Dieses Tutorial beschreibt, wie Daten, die tabellarisch vorliegen (wie etwa CSV etc.), unter Verwendung von openRefine ohne umfassende Programmierkentnisse in entityXML konvertiert werden können.
Schritt 1: Daten in OpenRefine laden
Zunächst müssen die Ausgangsdaten in OpenRefine geladen werden. Hierfür stehen zwei Wege zur Verfügung:
Weg 1: Neues OpenRefine Projekt erstellen und Daten laden
Liegen die tabellarischen Daten als CSV, EXCEL o.Ä. vor, dann wird in openRefine ein neues Projekt angelegt, in das die Daten über Create Project
reingeladen werden.
Abb 1: Ein neues Projekt erstellen
Hier kann man eine EXCEL- oder CSV-Datei auswählen und mit dem Klick auf Next
dem Einspielungsschritt zuführen.
In diesem Bereich wird dem zu erstellenden OpenRefine Projekt ein Titel zugewiesen und die Einspielungsparameter eingestellt. In der Regel muss man hier keine weiteren Einstellungen vornehmen. Mit einem Klicke oben rechts auf Create Project
wird ein neues OpenRefine-Projekt auf Grundlage der ausgewählten Daten erstellt.
Weg 2: Bestehendes OpenRefine Projekt importieren
Falls die Ausgangsdaten bereits als OpenRefine Projekt bestehen, kann die entsprechende Projektdatei (ein *.tar.gz
Archiv) einfach in OpenRefine im Bereich Import project
eingespiel werden.
Abb 3: Ein bestehendes Projekt importieren
Nun liegen die Daten in openRefine vor und können von hier ausgehend weiter verabeitet werden.
Schritt 2: GND-Reconciliation durchführen (optional)
Der im Folgenden beschriebene Schritt ist optional allerdings im Sinne der Datenqualität empfohlen. Wenn die Ausgangsdaten in openRefine eingespielt wurden, dann lohnt es sich, einen Datenabgleich mit der GND (ein sog. Daten-Reconciling) durchzuführen. Hierbei werden in den Daten enthaltene Informationen wie z.B. Namen, Lebensdaten oder Wikungsorte mit Informationen aus der GND abgeglichen, um mögliche Übereinstimmungen zu finden.
Ein Tutorial, wie man ein Daten-Reconciling in openRefine mit Hilfe von LOBID durchführt gibt es hier: https://blog.lobid.org/2018/08/27/openrefine.html
Schritt 3: Konzeptuelles Mapping auf entityXML erstellen
Nachdem die Ausgangsdaten nun in openRefine vorliegen und im Besten falle durch ein Reconciling mit der GND abgegelichen wurden, wird es Zeit sich einen Eindruck davon zu verschaffen, wie die vorliegende Datenstruktur auf entityXML abgebildet werden kann. Ziel dieses Schrittes ist es ganz konkret, die Datenfelder der vorliegenden Daten mit den Metadatenthermen aus entityXML zusammenzubringen, z.B. ein Feld Bevorzugter Namen
auf das entityXML-Element gndo:preferredName
. Als Grundstein für ein Verständnis des entityXML Datenmodells eignet sich die Recherche im entityXML Handbuch.
Handwerklich betrachtet wird ein konzeptuelle Mapping am niedrigschwelligsten in einer Tabelle angelegt, wobei jede Reihe einen Beschreibungsterm repräsentiert. Die Spalten in der entsprechenden Reihe weisen dann den Term des Ausgangsformats sowie den entsprechenden entityXML Term aus. Zusätzlich können weitere Spalten zusätzliche Anmerkungen enthalten.
Abb 4: Beispiel eines konzeptuellen Mapping
Schritt 4: Arbeit mit dem OpenRefine Templating Editor
Nachdem das konzeptuelle Mapping angefertigt wurde, kann darauf aufbauend ein Transformationstemplate für den OpenRefine Templating-Exporter entwickelt werden. Dafür werden einersteits Kentnisse darüber benötigt, wie ein entityXML Record aussieht. Andererseits muss man wissen, wie man die Daten aus den Reihen und Spalten in OpenRefine extrahiert.
Eine hilfreiche Ressource zum Einstieg in den Tamplatung-Exporter bietet Michael Markerts YouTube Tutorial zum Im- und Export von entityXML über openRefine. Weitere hilfreiche informationen findet man in der openRefine Dokumentation zum Templating Exporter.
Die Syntax, die verwendet wird, um Daten aus openRefine abzuziehen bzw. zu selektieren, heißt GREL Syntax. Diese Syntax wird benötigt, um die entsprechenden Datenfelder zu definieren, aus denen Inhalte während des Exports ausgelesen werden sollen. Das ist nicht ganz trivial, lässt sich aber mit den unten angegebenen Beispielen selbständig erlernen.
Den OpenRefine Templating-Exporter findet man, wenn man sich in der jeweiligen Projektansicht befindet: Oben rechts am Bildschirmrand unter Export
wird Templating...
ausgewählt. Dann öffnet sich der Exporter in einem Fenster mit zwei Spalten. In der linken Spalte finden sich 4 horizontal angeordnete Felder, in die die vorbereiteten Konversionstemplate eingegeben werden:
Abb 5: openRefine Templating Editor
-
Prefix: Hier wird der Anfang der Exportdatei festgelegt. Hierbei handelt es sich um den XML-Schnipsel, der bis zum ersten Record geht. Im Falle von entityXML wird hier also der Metadatenkopf einer entityXML Ressource "gebaut".
-
Row template: Hier wird das Recordtemplate, das auf jede Zeile angewendet wird, angelegt. Dies ist das Haupttemplate, in dem die Inhalte der einzelnen Felder ausgelesen werden und in entityXML Einträge konvertiert werden.
-
Row seperator definiert ein Trennzeichen für jeden Record. Wenn man XML templaten möchte, dann muss man hier nichts eingeben.
-
Suffix definiert den Abschluss der Exportdatei. Hiermit wird die XML-Struktur, die in Prefix aufgemacht wurde, wieder geschlossen.
Die rechte Spalte zeigt das Konversionsergebnis an. Hiermit kann man überprüfen, ob die entwickelten Templates und die darin verwendete Abfragesyntax wie gewünscht funktioniert.
Hinweis: Das Template sollte nicht im Templating-Exporter direkt implementiert werden, denn jedesmal, wenn man den Editor verlässt, werden alle Templates gelöscht! Man sollte das Template also in einer separaten Datei entwickeln und kann den Editor zum Testen verwenden!
Erstellen eines Exporttemplates
Für das Exporttemplate benötigt man nun also ein paar Kentnisse in GRELL (siehe oben) und drei XML-Fragmente, die in den Templating Exporter eingegeben werden, um am Ende eine zusammenhängende XML zu bekommen:
- den Metadatenkopf
- den Recordkörper und
- den XML-Abschluss
Der Metadatenkopf kommt in Prefix
, der Recordkörper kommt in Row template
, Row separator
wird frei gelassen, der XML-Abschluss kommt in Suffix
. Im Folgenden gebe ich Beispiele für alle Drei.
Der Metadatenkopf
Der Metadatenkopf bzw. der Anfang einer entityXML Datei bis zum ersten Record. Die Werte müssen natürlich für ein anderes Projekt angepasst werden. Hier kommt noch keine Dynamik in's Spiel, denn für den Metadatenkopf müssen keine Daten aus dem openRefine Datenset ausgelesen werden. Die Inhalte, die hier getampletet werden, sind also statischer Natur:
<entityXML xmlns="https://sub.uni-goettingen.de/met/standards/entity-xml#"
xmlns:gndo="https://d-nb.info/standards/elementset/gnd#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:skos="http://www.w3.org/2004/02/skos/core#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:dnb="https://www.dnb.de"
xmlns:geo="http://www.opengis.net/ont/geosparql#"
xmlns:ex="https://gitlab.gwdg.de/usikora/entityxml/tests"
xmlns:es="https://sub.uni-goettingen.de/met/standards/entity-xml-staging#"
xmlns:cst="https://sub.uni-goettingen.de/met/standards/cst">
<collection>
<metadata>
<title>Tiefenerschließung von Pflichtenbüchern des Markgraftums Brandenburg-Kulmbach-Bayreuth mit GND-Referenzierung der erfassten Beamten</title>
<abstract>Personendatensätze des Projektes "Tiefenerschließung von Pflichtenbüchern des Markgraftums Brandenburg-Kulmbach-Bayreuth mit GND-Referenzierung der erfassten Beamten".</abstract>
<provider id="staba" isil="DE-2046">
<title>Staatsarchiv Bamberg</title>
<abstract>Datenlieferant projektbezogene Forschungsdaten.</abstract>
<respStmt id="ToK">
<resp>Datenerfassung</resp>
<name>Tom Köcher</name>
</respStmt>
<respStmt id="JoH">
<resp>Projektleitung</resp>
<name>Johannes Haslauer</name>
<contact>
<mail>Johannes.Haslauer@staba.bayern.de</mail>
</contact>
</respStmt>
</provider>
<agency isil="DE-12">
<title>Bayerische Staatsbibliothek München (BSB)</title>
<abstract>Die Stabi München</abstract>
<respStmt id="ChE">
<resp>Datenredaktion</resp>
<name>Christine Erfurth</name>
<contact>
<mail>Christine.Erfurth@bsb-muenchen.de</mail>
</contact>
</respStmt>
</agency>
<revision status="opened">
<change when="2023-07-10" who="ChE">entityXML erzeugt.</change>
</revision>
</metadata>
<data xmlns:staba="https://www.gda.bayern.de/bamberg">
<list>
<title>Personendaten</title>
Der Recordkörper
Das eigentliche Record bzw. Row-Template inkl. GREL Funktionen und OpenRefine Expressions. Auch hier müssen die Werte natürlich auf die jeweiligen Strukturen anderer Projekte angepasst werden. An dieser Steller werden dynamisch Werte aus dem openRefine Datenset ausgelesen und in die gemappten entityXML Strukturen gebracht. Das hier angegebene Beispiel ist simple gehalten; man kann weitaus komplexere Abfragen bauen, aber für den Anfang sollte das hier ausreichen, um das Konzept klar werden zu lassen. Das vorliegende Beispiel geht davon aus, dass als Ausgangsdatenset ein Satz Personendaten vorliegt, der nun in jeweils eigene entityXML Personeneinträge konvertiert werden:
<person xml:id="" gndo:uri="{{if(cells["GND-Dublette"].recon.match.id!=null, cells["GND-Dublette"].recon.match.id, '')}}">
{{
if(cells["GND-Dublette"].recon.candidates.length()>0,
forEach(cells["GND-Dublette"].recon.candidates, v, '<staba:potentialMatch id="'+v.id+'">'+v.name+'</staba:potentialMatch>'),
'')
}}
<gndo:preferredName>
<gndo:forename>{{cells["Vorname"].value}}</gndo:forename>
<gndo:surname>{{cells["Nachname"].value}}</gndo:surname>
</gndo:preferredName>
{{
if(cells["abweichender Vorname"].value!=null,
'<gndo:variantName><gndo:forename>'+cells["abweichender Vorname"].value+'</gndo:forename><gndo:surname>'+cells["Nachname"].value+'</gndo:surname></gndo:variantName>',
'')
}}
{{
if(cells["abweichender Nachname"].value!=null,
'<gndo:variantName><gndo:forename>'+cells["Vorname"].value+'</gndo:forename><gndo:surname>'+cells["abweichender Nachname"].value+'</gndo:surname></gndo:variantName>',
'')
}}
{{
if(cells["abweichender Nachname 2"].value!=null,
'<gndo:variantName><gndo:forename>'+cells["Vorname"].value+'</gndo:forename><gndo:surname>'+cells["abweichender Nachname 2"].value+'</gndo:surname></gndo:variantName>',
'')
}}
{{
if(cells["abweichender Nachname 3"].value!=null,
'<gndo:variantName><gndo:forename>'+cells["Vorname"].value+'</gndo:forename><gndo:surname>'+cells["abweichender Nachname 3"].value+'</gndo:surname></gndo:variantName>',
'')
}}
{{
if(cells["charakteristischer Beruf"].recon.matched,
'<gndo:professionOrOccupation gndo:type="significant" gndo:ref="https://d-nb.info/gnd/'+cells["charakteristischer Beruf"].recon.match.id+'">'+cells["charakteristischer Beruf"].recon.match.name+'</gndo:professionOrOccupation>',
'')
}}
{{
if(cells["Beruf 1"]!=null,
if(cells["Beruf 1"].recon.matched, '<gndo:professionOrOccupation gndo:ref="https://d-nb.info/gnd/'+cells["Beruf 1"].recon.match.id+'">'+cells["Beruf 1"].recon.match.name+'</gndo:professionOrOccupation>',
'<gndo:professionOrOccupation>'+cells["Beruf 1"].value+'</gndo:professionOrOccupation>'),
'')
}}
{{
if(cells["Beruf 2"]!=null,
if(cells["Beruf 2"].recon.matched, '<gndo:professionOrOccupation gndo:ref="https://d-nb.info/gnd/'+cells["Beruf 2"].recon.match.id+'">'+cells["Beruf 2"].recon.match.name+'</gndo:professionOrOccupation>',
'<gndo:professionOrOccupation>'+cells["Beruf 2"].value+'</gndo:professionOrOccupation>'),
'')
}}
{{
if(cells["Wirkungszeit"]!=null, '<gndo:periodOfActivity>'+cells["Wirkungszeit"].value+'</gndo:periodOfActivity>',
'')
}}
{{
if(cells["Lebensdaten"]!=null, '<staba:dateOfBirthandDeath>'+cells["Lebensdaten"].value+'</staba:dateOfBirthandDeath>',
'')
}}
{{
if(cells["Geburtsort"]!=null,
if(cells["Geburtsort"].recon.matched, '<gndo:placeOfBirth gndo:ref="https://d-nb.info/gnd/'+cells["Geburtsort"].recon.match.id+'">'+cells["Geburtsort"].recon.match.name+'</gndo:placeOfBirth>',
'<gndo:placeOfBirth>'+cells["Geburtsort"].value+'</gndo:placeOfBirth>'),
'')
}}
{{
if(cells["Wirkungsort"]!=null,
if(cells["Wirkungsort"].recon.matched, '<gndo:placeOfActivity gndo:ref="https://d-nb.info/gnd/'+cells["Wirkungsort"].recon.match.id+'">'+cells["Wirkungsort"].recon.match.name+'</gndo:placeOfActivity>',
'<gndo:placeOfActivity>'+cells["Wirkungsort"].value+'</gndo:placeOfActivity>'),
'')
}}
{{
if(cells["Biographische Angaben"]!=null, '<gndo:biographicalOrHistoricalInformation>'+cells["Biographische Angaben"].value+'</gndo:biographicalOrHistoricalInformation>',
'')
}}
</person>
Der XML-Abschluss
Der XML-Abschluss, damit die Datei auch anständig abgeschlossen wird. Wie der Metadatenkopf ist auch dieser Teil statisch und muss nicht weiter angepasst werden.
</list>
</data>
</collection>
</entityXML>
Anwendung des Templating-Exporters
Sind die drei Templates fertig und ausentwickelt, kann man den Export durchführen: Die drei XML-Fragmente werden in die entsprechenden Felder im Templating-Exporter kopiert und mittels Klick auf Export
ausgeführt.
OpenRefine fragt im Anschluss an die Konversion nach dem Ort, wo es das Ergebnis abspeichern soll. Nun kann man das Ergebnis als XML Datei abspeichern, indem man die voreingestellte Endung *.txt durch *.xml ersetzt.
Schritt 5: Aufbereitung der entityXML Ressource
Nun liegen die Ausgangsdaten in einer ersten entityXML Version vor, die als vorläufig betrachtet werden sollte. Diese Ressource muss nun in diesem Schritt entsprechend redaktionell aufbereitet werden. Dabei unterstützt die mitgelieferte Validierung. Ziel dieses Schrittes ist die Erstellung einer entityXML Ressource, die den jeweiligen Ansprüchen eines Projekts an die eigenen Forschungsdaten sowie dem entityXML Datenmodell genügt.
In unserem obrigen Beispiel wird z.B. keine ID für jeden Record erzeugt. Das müsste man nun händisch in der resultierenden entityXML nachtragen, oder man schreibt sich eine Anschlußkonversion in XSLT, die die entsprechenden Anereicherungen vornimmt. Man kann auch einfach in den Ausgangsdaten lokale IDs für jeden Eintrag hinterlegen, die dann ebenfalls in Schritt 4 mit ausgelesen werden können.
Schritt 6: MARC-XML Konversion
Das entityXML Framework für oXygen XML bietet die Möglichkeit auf Knopfdruck eine MARC-XML Ressource aus einer entityXML Ressource heraus zu konvertieren. Damit besteht ein systematischer Weg um von entityXML direkt in GND-gültiges MARC21 zu konvertieren.
Dafür klickt man bei installiertem Framework im oXygen XML Editor während man die entsprechende entityXML Ressource geöffnet hat, die man konvertieren möchte, auf den Maulschlüssel im oberen Menübereich (Transformation-Scenarios konfigurieren) und wählt hier die entityXML: XML2MARC-xml
Konversion aus. Abschließend bestätigt man mit "Zugeordnete anwenden" und wird nach einem Speicherort für die MARC-Datei gefragt.
Abb 6: Die redaktionell aufgearbeitete entityXML Datei in oXygenXML