<oXygen/>-Funktion "Transparenzwähler für Tags"

Gerade entdeckt: Über die Konfiguration der Werkzeugleiste lässt sich in <oXygen/> oXygen 18 unter dem Punkt "Quelle" das Werkzeug "Transparenzwähler für Tags" auswählen. Dieses Werkzeug ändert die Darstellung des XML-Quelltextes und erlaubt es, den Kontrast zwischen Markup und Inhalten zu ändern und damit aufgabenbezogen die Lesbarkeit von Markup bzw. Inhalt erhöhen, weil das jeweils andere durch Reduktion des Kontrasts in den Hintergrund rückt.

Ich kann mir vorstellen, dass das Ausblenden des Markups für die inhaltliche Korrektur tief getaggter Text hilfreich sein kann. Oder umgekehrt das Ausblenden des Inhalts für den Entwurf von XSL Transformationen.

Die unterschiedlichen Transparenzeinstellungen Die unterschiedlichen Transparenzeinstellungen (oXygen 18, Windows)

HAB goes eduroam

Update: Nach dem Wechsel von OpenSSL auf GnuTLS musste ich die Option ca_path auskommentieren, um eine Verbindung zum eduroam-Netzwerk herzustellen.

Seit kurzem nimmt die Herzog August Bibliothek auch an eduroam teil. Damit können sich nicht nur Gastwissenschaftler mit ihren lokalen Anmeldedaten am hiesigen WLAN anmelden, sondern auch umgekehrt Mitarbeiter mit hiesigen Anmeldedaten am WLAN anderer Einrichtungen. Vorausgesetzt natürlich, dass die jeweilige Einrichtung sich auch an eduroam beteiligt.

Die Einrichtung auf dem Laptop war ein Kinderspiel. Einfach /etc/wpa_supplicant/wpa_supplicant.conf um folgenden Eintrag ergänzen:

network={   ssid="eduroam"   scan_ssid=1   key_mgmt=WPA-EAP   pairwise=CCMP   group=CCMP TKIP   eap=PEAP   identity="maus@hab.de"   domain_suffix_match="radius1.hab.de" #  Bei Verwendung von GnuTLS ca_path auskommentieren #  ca_path="/etc/ssl/certs"   password="XXXXXXXXXXXXXXXXXXXXXXXX"   anonymous_identity="anonymous@hab.de"   phase2="auth=MSCHAPV2" }

Die einzige Hürde beim Einrichten war, dass in der Nähe meines Büros noch ein alter AccessPoint steht, der als Identitätsnachweis nur ein selbstsigniertes Zertifikat anbietet.

HAB goes eduroam, Teil 2

Auch die Einstellungen auf einem Android-Smartphone Android 8.1 sind überschaubar und können ohne Zusatzanwendung vorgenommen werden. Im Verbindungsdialog folgende Einstellungen auswählen:

EAP-Methode
PEAP
Phase 2-Authentifizierung
MSCHAPV2
CA-Zertifikat
Systemzertifikat verwenden
Domain
radius1.hab.de
Identität
maus@hab.de
Anonyme Identität
anonymous@hab.de

A quick one: Use Metafacture to create a list of records with cataloging errors

Some records in our library catalog contain an error that causes trouble when we distribute catalog data to national aggregators like the Zentrales Verzeichnis Digitalisierter Drucke (ZVDD) central access point to printed works from the 15th century up to today, digitized in Germany. The catalogers made a typo and didn't separate the name of the publisher and the place of publication.

Metafacture is a really helpful suite of tools when working with a comparatively large set of records in a somewhat unwieldy format. The following Metamorph transformation runs over a dump of our catalog and outputs a list that contains the record's primary key Pica production number, PPN, an indicator of the resource type, and the erroneous publication statement.

<metamorph xmlns="http://www.culturegraph.org/metamorph" version="1" entityMarker="$">   <rules>     <!-- Titel, bei denen Verlag und Ort nicht getrennt sind            -->     <!-- Bsp. http://uri.hab.de/instance/proxy/opac-de-23/391719076.xml -->     <!-- hier 033A $p[Strassburg: Prüss]                                -->     <combine name="" value="${ppn} - ${mat} - ${fehler-verlag}">       <data source="003@$0" name="ppn"/>       <data source="002@$0" name="mat">         <substring start="0" end="1"/>       </data>       <data source="033A$p" name="fehler-verlag">         <regexp match=".+: .+" format="${0}"/>         <normalize-utf8/>       </data>     </combine>   </rules> </metamorph>

If the subfield p of the field 033A matches the specified regular expression, and both the subfield 0 of field 003@ and subfield 0 of field 002@ are present, combine these three fields to an unnamed output entity. Because 002@ and 003@ are always present, the combine acts as a filter and generates an output entity only if the erroneous 033A is detected.

I run this morph with a simple flux pipeline.

default src = "s:\\edoc\\ed000242\\2017\\20170429-title.pp"; default dst = "stdout"; src| open-file| as-records| decode-pica| morph(FLUX_DIR + morph)| encode-literals| write(dst);

Turns out that only 678 of appr. 1.2 million records or 0.06% are affected. This speaks volumes for the dedication of our staff and makes the problem managable.

Quick'n'dirty: Compile XSL-FO to PDF from Emacs

Execute Apache FOP from within Emacs and compile current file to PDF (or any other supported output formats).

;;; xslfo-mode.el --- Minor mode for working with XSL-FO files (defvar xslfo-fop-outspec '(("pdf"    . "pdf")                             ("rtf"    . "rtf")                             ("txt"    . "txt")                             ("at"     . "xml")                             ("if"     . "xml")                             ("png"    . "png")                             ("tiff"   . "tiff")                             ("ps"     . "ps")                             ("pcl"    . "pcl")                             ("pdfa1b" . "pdf"))   "Apache FOP output formats.") (define-minor-mode xslfo-mode   "Minor mode for working with XSL-FO files."   :init-value nil   :lighter "XSL-FO"   :keymap `((,(kbd "C-c C-c") . xslfo-compile))) (defmacro xslfo-fop-outspec-extension (name)   `(or (cdr (assoc ,name xslfo-fop-outspec)) "bin")) (defun xslfo-compile (&optional arg)   (interactive "P")   (let* ((outspec (if arg (completing-read "Output format: " (mapcar #'car xslfo-fop-outspec) #'stringp t (caar xslfo-fop-outspec))                     "pdf"))          (srcfile (or buffer-file-name (error "Buffer not visiting a file")))          (outfile (concat (expand-file-name (file-name-sans-extension srcfile)) "." (xslfo-fop-outspec-extension outspec)))          (bufname (concat "*XSL-FO: " outfile "*")))     (with-current-buffer (get-buffer-create bufname)       (erase-buffer)       (when (= 0 (apply #'call-process (executable-find "fop") nil t t (list (concat "-" outspec) outfile srcfile)))         (message "Wrote %s" outfile)         (display-buffer bufname))))) (provide 'xslfo-mode) ;;; xslfo-mode.el ends here xslfo-mode

Identitätstransformation in XSLT 3.0

Eine Identitätstransformation ist bei meiner Arbeit oft Ausgangspunkt von inkrementellen Änderungen einer XML-Datei. Während man in XSLT 2.0 und XSLT 1.0 noch ein eigenes Template schreiben musste, dass rekursiv alle Knoten des Quelldokuments kopiert, so kürzt sich die Identitätstransformation in XSLT 3.0 auf eine Zeile zusammen.

<xsl:transform version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">   <xsl:mode on-no-match="shallow-copy"/> </xsl:transform> Identitätstransformation in XSLT 3.0

Das on-no-match wählt die integrierten Verarbeitungsregeln built-in template rules aus, die für den unbenannten Modus unnamed mode angewendet werden. In 3.0 stehen sechs verschiedene Regelsätze zur Verfügung.

text-only-copy
Nur der Text des Eingabedokuments wird in das Ausgabedokument kopiert.
Dieser Modus entspricht den integrierten Verarbeitungsregeln der Vorgängerversionen.
deep-copy
Knoten werden unverändert und einschließlich ihrer Kindknoten in das Ausgabedokument geschrieben. Verarbeitungsregeln werden nicht auf die Kindknoten angewendet.
shallow-copy
Knoten werden unverändert in das Ausgabedokument geschrieben. Verarbeitungsregeln werden auf die Kindknoten angewendet.
deep-skip
Knoten werden ignoriert. Verarbeitungsregeln werden nicht auf die Kindknoten angewendet.
shallow-skip
Knoten werden ignoriert. Verarbeitungsregeln werden auf die Kindknoten angewendet.
fail
Die Verarbeitung wird abgebrochen.

Hallo XSLT 3.0

Gestern hatte ich erstmals die Gelegenheit, einige der Neuerung in XSLT 3.0 nutzen zu können. Die (selbstgestellte) Aufgabe bestand darin, die RDF/XML-kodierten Metadaten zu meiner Person in JSON-LD umzuwandeln.

Im Zentrum stand die mit XSLT 3.0 eingeführte native Verarbeitung von JSON. Die Funktionen json-to-xml und xml-to-json wandeln JSON in XML bzw. umgekehrt XML in JSON. Die Spezifikation definiert eine XML-Repräsentation, die Ausgangs- bzw. Endpunkt der Umwandlung ist.

Die Hauptaufgabe meiner Transformation besteht darin, die in RDF/XML kodierten Daten in die XML-Repräsentation von JSON umzuwandeln. Diese Umwandlung ist straight forward: Ich erstelle eine json:map, die ich mit Schlüssel-Wert-Paaren der ausgewählten Informationen befülle.

Da ich die Umwandlung im Stile des push processing Kay, Michael. XSLT 2.0 and XPath 2.0, 4th Edition. Indianapolis, IN: Wiley Publishing, 2008. S. 74ff schreibe, muss ich sie in zwei Schritten vornehmen. Der erste Schritt erstellt Einträge in der json:map ohne gleiche Eigenschaften zu gruppieren.

Also aus

<foaf:Person rdf:about="http://dmaus.name#me">   <owl:sameAs rdf:resource="http://orcid.org/0000-0001-9292-5673"/>   <owl:sameAs rdf:resource="https://orcid.org/0000-0001-9292-5673"/>   <owl:sameAs rdf:resource="http://d-nb.info/gnd/1141920794"/>   … </foaf:Person>

und

<xsl:template match="owl:sameAs">   <json:string key="sameAs">{@rdf:resource}</json:string> </xsl:template>

wird im ersten Schritt

<json:map>   <json:string key="@context">http://schema.org</json:string>   <json:string key="@type">Person</json:string>   <json:string key="@id">http://dmaus.name#me</json:string>   <json:string key="sameAs">http://orcid.org/0000-0001-9292-5673</json:string>   <json:string key="sameAs">https://orcid.org/0000-0001-9292-5673</json:string>   <json:string key="sameAs">http://d-nb.info/gnd/1141920794</json:string>   … </json:map>

Der zweite Schritt gruppiert gleiche Eigenschaften in ein json:array.

<xsl:template name="normalize">   <xsl:param name="json-map" required="true"/>   <json:map>     <xsl:for-each-group select="$json-map/*" group-by="@key">       <xsl:choose>         <xsl:when test="count(current-group()) eq 1">           <xsl:sequence select="current-group()"/>         </xsl:when>         <xsl:otherwise>           <json:array key="{current-grouping-key()}">             <xsl:for-each select="current-group()">               <xsl:copy>                 <xsl:sequence select="node()"/>               </xsl:copy>             </xsl:for-each>           </json:array>         </xsl:otherwise>       </xsl:choose>     </xsl:for-each-group>   </json:map> </xsl:template>

Das Ergebnis des zweiten Schritts kann ich dann mit xml-to-json umwandeln und in meine Webseite einfügen.

<xsl:template match="foaf:Person[@rdf:about = $me]">   <xsl:variable name="json-ld">     <xsl:apply-templates select="." mode="json.header"/>   </xsl:variable>   …   <script type="application/ld+json">     <xsl:value-of select="xml-to-json($json-ld)"/>   </script>   … </xsl:template>

Merke, dass ich im ersten Schritt auch ein weiteres Feature von XSLT 3.0 benutze. Mit der Einführung von text value templates wurde das Konzept der bereits in XSLT 1.0 definierten attribute value templates verallgemeinert. Wenn die Expansion von text value templates aktiviert ist, dann lassen sich auch in Elementinhalten XPath-Ausdrücke in geschweifte Klammern fassen, die während der Transformation mit dem Ergebnis des XPath-Ausdrucks ersetzt werden.

PDF-Lesezeichen und Inhaltsverzeichnis mit XSL-FO

Um praktische Erfahrungen mit XSL-FO zu sammeln, erstelle ich aus den im Projekt Selbstzeugnisse der Frühen Neuzeit in der Herzog August Bibliothek publizierten Daten einfache PDF-Dateien.

Heute habe ich mich mit dem Erstellen von PDF-Lesezeichen beschäftigt. Im PDF der Edition sollen zusätzlich zum Inhaltsverzeichnis auch PDF-Lesezeichen enthalten sein, mit denen der Benutzer im Dokument navigieren kann.

Da Lesezeichen und Inhaltsverzeichnis die selbe Information abbilden, habe ich ein Template geschrieben, das die benötigten Informationen in einem Zwischenformat zusammenstellt. Der Einfachheit halber habe ich das TEI-Vokabular für die Struktur der Liste gewählt. Für jeden Eintrag wird ein item erzeugt, in dessen corresp das Sprungziel abgelegt wird. Das Label des Eintrags wird in einem label angegeben.

<xsl:template name="inhaltsverzeichnis-einträge">   <list>     <xsl:for-each select="text/front//div/head[count(ancestor::div/head) eq 1]">       <item corresp="{generate-id()}">         <label><xsl:value-of select="normalize-space()"/></label>       </item>     </xsl:for-each>     <item corresp="diarium">       <label>Ephemerides. Sive Diarium (1594-1635)</label>       <list>         <xsl:for-each select="text/group/text/body">           <item corresp="{generate-id()}">             <label>               <xsl:value-of>                 <xsl:value-of select="format-date((.//div/head/date[1]/@when)[1], '[Y]')"/>                 <xsl:text> (</xsl:text>                 <xsl:value-of select="format-date((.//div/head/date[1]/@when)[1], '[D01].[M01].')"/>                 <xsl:text>–</xsl:text>                 <xsl:value-of select="format-date((.//div/head/date/@when)[last()], '[D01].[M01].[Y]')"/>                 <xsl:text>)</xsl:text>               </xsl:value-of>             </label>           </item>         </xsl:for-each>       </list>     </item>     <item corresp="register">       <label>Register</label>     </item>   </list> </xsl:template>

Diese Inhaltsangaben werden nun durch je ein Template für Lesezeichen und Inhaltsverzeichnis formatiert. Die Hierarchie des Inhalts bilde ich im Inhaltsverzeichnis durch Einrückung der Einträge an.

<xsl:template match="item" mode="inhaltsverzeichnis">   <fo:block margin-left="{(count(ancestor::list) - 1)}em">     <fo:basic-link internal-destination="{@corresp}">       <xsl:value-of select="label"/>       <fo:inline>         <fo:leader leader-pattern="dots"/>       </fo:inline>       <fo:page-number-citation ref-id="{@corresp}"/>     </fo:basic-link>   </fo:block>   <xsl:apply-templates mode="#current"/> </xsl:template> <xsl:template match="item" mode="lesezeichen">   <fo:bookmark internal-destination="{@corresp}">     <fo:bookmark-title>       <xsl:value-of select="label"/>     </fo:bookmark-title>     <xsl:apply-templates mode="#current"/>   </fo:bookmark> </xsl:template>

Das Ergebnis ist ganz passabel!

Screenshot Lesezeichen im PDF

Provide a random UUID to XSLT with XProc <p:uuid>

Create a step that acts as source of the UUID. The step provides an XML document with a single uuid-element at its primary output port result. The uuid has a single attribute value which contains the UUID as value.

<p:uuid version="4" match="@value" name="uuid-source">   <p:input port="source">     <p:inline>       <uuid value=""/>     </p:inline>   </p:input> </p:uuid>

Connect the step to the p:with-param inside the p:xslt step.

<p:xslt>   …   <p:with-param name="uuid" select="/uuid/@value">     <p:pipe step="uuid-source" port="result"/>   </p:with-param>   … </p:xslt>

Done.

Rückblick XML Prague 2018

XML Prague stand dieses Jahr für mich im Zeichen der Qualitätssicherung. Am unconference day hat Matthieu Ricaud-Dussarget eine Sammlung von Schematron-Regeln vorgestellt, mit dem in seinem Team XSLT-Stylesheets auf problematische Konstruktionen und die Einhaltung von Konventionen geprüft werden. Im Anschluss trafen sich bestehende und prospektive Nutzer von XSpec, einem Testframework für XSLT, XQuery und Schematron. Ich habe im letzten Jahr damit begonnen, einige Transformationen und Schemata mit XSpec abzusichern und kann es nur weiterempfehlen.

Der Vortrag Using Maven with XML Projects von Christophe Marchand and Matthieu Ricaud-Dussarget am Folgetag hat mich (wieder einmal) daran erinnert, mich näher mit continuous integration zu beschäftigen. Kommt mir zwar vor wie overkill, aber hey: Vielleicht ist das Aufsetzen eines CI-Systems einfacher, als ich denke?!

Letztlich am Samstag der XSLT-Checker der data2type GmbH. Ein System, mit dem sich Transformationsregeln ermitteln lassen, die in einem XSLT-Stylesheet nicht mehr verwendet werden. Auch hier ein im Grunde recht einfaches Prinzip: Das betreffende Stylesheet wird so modifiziert, dass es für jede Regeln eine Nachricht ausgibt, wenn sie greift. Dann wird eine repräsentatitve Menge von Quelldateien transformiert und am Ende geschaut, welche Regeln keine Nachricht produziert haben.

Darüber hinaus war allein der Vortrag von Hans-Juergen Rennau den Besuch wert. Der Codename SHAX steht für die Idee einer XML und RDF übergreifenden Modellierungssprache, mit der sich Beschränkungen zulässiger Eigenschaften von Informationsobjekten ausdrücken lassen. Ein in SHAX beschriebenes Modell lässt sich in Regeln für ein XML Schema, ein JSON Schema oder eine RDF Shape Expression (SHACL) übersetzen. Informationen können dann in den korrespondierenden Formaten (XML, JSON oder RDF) produziert, konsumiert und vor allem validiert werden.

Am Ende des Projektes Emblematica Online sind wir genau auf diesen Punkt gestoßen: Wir publizieren unsere Embleme als "kanonisches" RDF/XML, dass wir mit einem Schema beschreiben. In der (noch fälligen) Dokumentation der publizierten Metadaten würden wir genau die selben Angaben machen. Zwar ist das Projekt vorbei, doch wenn ich RDF Shape Expressions formulieren wollen würde, dann müsste ich die selben Angaben erneut wiederholen. SHAX to the rescue?

Letztlich bot der letzte Konferenztag natürlich auch die Gelegenheit, den 20. Geburtstag der XML-Spezifikation zu feiern. Stilecht mit einer kurzen Aufführung des XML-Tanzes.

Oh, und save the date: Markup UK am 9. und 10. Juni 2018 in London.

XML Prague – Statusupdate

XProc.Next Working Group

Die ersten zwei Tage meines Arbeitsprogramms in Prag sind vorüber und mein Eindruck ist, dass die XProc.Next-Arbeitsgruppe wieder einen großen Schritt in Richtung XProc 3.0 gemacht hat. Wenn alles gut geht, dann werden wir eine Vorabversion (Candidate Release) der Spezifikation im Juni veröffentlichen.

Heute: unconference day. Geplant ist der Besuch der beiden Workshops zu paged media sowie des Schematron und das XSpec Anwendertreffen. Der Workshop "XML and Emacs" fällt leider aus.

XML Prague 2018

Auch dieses Jahr zieht es mich im Februar gen Osten zur diesjährigen XML Prague.

Neben dem Meeting der XProc Community Group am 6. und 7. freue ich mich besonders auf den Workshop "XML and Emacs" am unconference day und die Vorträge von Hans-Juergen Rennau (Combining graph and tree: writing SHAX, obtaining SHACL, XSD and more), Bert Willems (Assisted Structured Authoring using Conditional Random Fields) und dem wunderbar eloquenten Steven Pemberton (Form, and Content).

Liste der Workshops und Sessions der XML Prague 2018

Zotero Standalone ohne Abhängigkeit von GTK+ 3 und DBus

Mit Version 5.0 der Literaturverwaltung Zotero hat es eine für mich einschneidende Veränderung gegeben: Erstmals gibt es Zotero nicht mehr als in Firefox installierbare Erweiterung, sondern nur noch und ausschließlich als alleinstehendes Programm. Der Grund für diese Änderung liegt im Entschluss von Mozilla, das bisher verwendete System für Erweiterungen nicht mehr zu unterstützen.

Soweit, so schlecht. Dummerweise basiert die offizielle Version von Zotero Standalone auf einer Firefox Laufzeitumgebung, die ihrerseits von Systembibliotheken DBus und GTK+ 3 abhängt, die auf meinen System nicht installiert sind und nicht installiert werden.

Ich muss mir also meine eigene Zotero Standalone bauen, die auf einer ebenfalls selbst gebauten Firefox Laufzeitumgebung basiert. Eine Anleitung im Zotero Wiki beschreibt, wie Zotero Standalone aus den Quellen erstellt wird. Da meine Linux-Distribution im Moment nur eine ältere Version von NodeJS bereitstellt, verwende ich ein stabiles Devuan, dass ich in Form eines QEMU Festplatten-Abbildes als Entwicklungsumgebung nutze.

Zwar liefert das aktuelle Devuan 1.0 auch nur die Version 6 von NodeJS benötigt wird mindestens Version 8, aber NodeSource bietet die benötigte Version in einem Repository an, dass ich in der Paketverwaltung von Devuan ergänzen kann.

root@devuan % wget -qO- https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - root@devuan % echo 'deb https://deb.nodesource.com/node_9.x jessie main' > /etc/apt/sources.list.d/nodesource.list root@devuan % echo 'deb-src https://deb.nodesource.com/node_9.x jessie main' > /etc/apt/sources.list.d/nodesource.list root@devuan % apt-get install apt-transport-https root@devuan % apt-get update root@devuan % apt-get install nodejs

Mit der erforderlichen Version von NodeJS ausgestattet kopiere ich die Firefox Laufzeitumgebung von meinem System auf das Festplatten-Abbild.

dmaus@x220i % sudo qemu-nbd -c /dev/nbd0 virtual/devuan.img dmaus@x220i % sudo fdisk -l /dev/nbd0 dmaus@x220i % sudo mount /dev/nbd0p1 /mnt/ dmaus@x220i % sudo cp -ra /usr/lib/firefox /mnt/home/dmaus dmaus@x220i % sudo umount /mnt dmaus@x220i % sudo qemu-nbd -d /dev/nbd0

Und nun kann es losgehen. Ich folge der Anleitung bis zu dem Schritt, in dem die Firefox Laufzeitumgebung heruntergeladen und vorbereitet wird. Da ich meine eigene Laufzeitumgebung verwenden will, erstelle ich eine Shellscript, das die Laufzeitumgebung aus dem Homeverzeichnis kopiert und dann anpasst.

#!/bin/bash set -euo pipefail CALLDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" . "$CALLDIR/config.sh" # # Make various modifications to omni.ja # function modify_omni {  … wie fetch_xulrunner.sh … } # Add devtools server from browser omni.ja function extract_devtools {  … wie fetch_xulrunner.sh …   } mkdir -p xulrunner cd xulrunner rm -rf firefox-x86_64 cp -ra ~/firefox ./firefox-x86_64 cd firefox-x86_64 modify_omni extract_devtools cd .. echo Done

Als letztes entferne ich die Architektur i686 aus dem Script build.sh, da ich nur die 64bit-Variante erstelle.

diff --git a/build.sh b/build.sh index b6a2fd2..d736969 100755 --- a/build.sh +++ b/build.sh @@ -448,7 +448,7 @@ fi    # Linux  if [ $BUILD_LINUX == 1 ]; then - for arch in "i686" "x86_64"; do + for arch in "x86_64"; do

Fertig! Der letzte Schritt der Anleitung erzeugt ein Verzeichnis mit Zotero Standalone und meiner Laufzeitumgebung. Ich kopiere es vom Festplatten-Abbild in ein lokales Installationsverzeichnis und komme nun auch in den Genuss von Zotero 5.

Zotero Standalone @ x220i

Integration der ICONCLASS-Klassifikation in die Emblembuchbeschreibungen des Projektes »Emblematica Online«

Neben der Entwicklung einer Kernontologie für die Modellierung der in Wolfenbüttel erschlossenen Embleme vgl. Cole et al. 2017 war die Erweiterung der Datenbasis ein wesentliches Ziel des Projektes »Emblematica Online — Linked Open Emblem Data«. Wie bereits in den Vorprojekten wurden Embleme ausgewählter Emblembücher ermittelt und mit einem persistenten Identifikator versehen. Die inhaltliche Erschließung der Embleme erfolgte durch das Bildarchiv Foto Marburg, das für die bildlichen Darstellung der Embleme Systemstellen der ICONCLASS-Notation vergab.

Die Emblembücher sind als XML-Dokumente geführt, in denen die wesentlichen Textstrukturen mit dem Vokabular der Text Encoding Initiative (TEI) kodiert werden. Die Bestandteile eines Emblems – Motto, Pictura, Subscriptio – sind je als Abschnitt div kodiert, der durch ein type-Attribute näher als Motto, Pictura bzw. Subscriptio gekennzeichnet ist. Die Zugehörigkeit zu einem bestimmten Emblem ist durch Belegung des n-Attributs ausgedrückt, das mit der Identifikationsnummer des jeweiligen Emblems belegt ist.

<div type="emblem_pictura" n="E018850" facs="#drucke_xb-4362_00122"/> <div type="emblem_motto" n="E018850" facs="#drucke_xb-4362_00122">   <p xml:lang="de">So muß es mir ergehn, Soll ich sonst fäste Stehn.</p> </div> TEI-kodiertes Emblem E018850

Die Daten wurden von Foto Marburg über eine OAI-Schnittstelle als Emblembuchbeschreibung im Emblem Schema kodiert zur Verfügung gestellt. Hier sind die Emblembestandteile durch spezielle Elemente ausgezeichnet. Notation und bevorzugte Bezeichnung einer ICONCLASS-Klassifikation sind durch Elemente aus dem Namensraum des Simple Knowledge Organization System wiedergegeben, die zu einer Systemstelle gehörenden deutschsprachigen Schlagwörter durch Elemente des Emblem Schema-Namensraums.

<emblem:emblem globalID="http://hdl.handle.net/10111/EmblemRegistry:E018850">   <emblem:motto>     <emblem:transcription xlink:href="http://diglib.hab.de/drucke/xb-4362/start.htm?image=00122" xml:lang="de">       <tei:p xml:lang="de">So muß es mir ergehn, Soll ich sonst fäste Stehn.</tei:p>     </emblem:transcription>   </emblem:motto>   <emblem:pictura medium="engraving" xlink:href="http://diglib.hab.de/drucke/xb-4362/start.htm?image=00122">     <emblem:iconclass>       <skos:notation>86(SO MUSS ES MIR ERGEHN, SOLL ICH SONST FÄSTE STEHN)</skos:notation>       <skos:prefLabel xml:lang="de">Sprichwörter, Redewendungen, etc.</skos:prefLabel>       <emblem:keyword xml:lang="de">Redewendung</emblem:keyword>       <emblem:keyword xml:lang="de">Sprichwort</emblem:keyword>     </emblem:iconclass>     …   </emblem:pictura> </emblem:emblem> Emblem E018850 in Emblem-Schema

Um die ICONCLASS-Erschließung in die TEI-kodierten Emblembuchbeschreibungen zu integrieren müssen bevorzuge Bezeichnung, Notation und zur Notation gehörende Schlagwörter als index und term-Elemente unterhalb der die bildlichen Darstellungen tragenden Abschnitte eingebracht werden.

<div type="emblem_pictura" n="E018850" facs="#drucke_xb-4362_00122">   <p>     <index indexName="notation" facs="#drucke_xb-4362_00122">       <term xml:lang="de" key="86(SO MUSS ES MIR ERGEHN, SOLL ICH SONST FÄSTE STEHN)" type="ICONCLASS">         Sprichwörter, Redewendungen, etc.       </term>       <index indexName="bsw" facs="#drucke_xb-4362_00122">         <term xml:lang="de" key="86(SO MUSS ES MIR ERGEHN, SOLL ICH SONST FÄSTE STEHN)" type="ICONCLASS">           Redewendung         </term>         <term xml:lang="de" key="86(SO MUSS ES MIR ERGEHN, SOLL ICH SONST FÄSTE STEHN)" type="ICONCLASS">           Sprichwort         </term>       </index>     </index>     …   </p> </div> Integrierte ICONCLASS-Erschließung für Emblem E018850

Integration der Erschließungsdaten

Flußdiagramm Flußdiagramm des Ergänzungsalgorithmus

Ein Algorithmus der die Erschließungsdaten im Emblem Schema in die TEI-kodierten Emblembuchbeschreibungen einbringt lässt sich wie folgt beschreiben.

  • Für jedes in den Erschließungsdaten enthaltene Emblembuch wird die Adresse der TEI-kodierten Emblembuchbeschreibung ermitteln und die entsprechende Datei geladen.
  • Für jede in der Datei verzeichnete Pictura werden die zugehörigen emblem:iconclass-Elemente in den Erschließungsdaten ermitteln, in die gewünschten TEI-Strukturen umgewandelt und an den die Pictura repräsentierenden Abschnitt angehangen.
  • Wenn alle Picturae abgearbeitet sind, dann wird ein Änderungsvermerk in den Kopfbereich der Emblembuchbeschreibung eingefügt und die Datei gespeichert.

Umsetzung als XProc 1.0 Pipeline

Dieser Algorithmus wurde in leicht modifizierter Form als XProc 1.0 Pipeline implementiert. Anstatt die Erschließungsdaten für jede Pictura gesondert in TEI umzuwandeln, wurden die emblem:iconclass-Elemente an die Picturae-Abschnitte angehangen und nach Abarbeitung aller Picturae eines Emblembuchs in einer Transformation umgewandelt.

Die Auswahl aller zu einer bildlichen Darstellung gehörenden emblem:iconclass-Elemente wurde in einem eigenen Schritt implementiert. Der Schritt bekommt die ID des Emblems und den Permalink der die Darstellung zeigenden Seite als Parameter übergeben (Zeile 6 und 7). Er besitzt einen primären Eingabe- und einen primären Ausgabeport, über den die Erschließungsdaten ein- bzw. das Ergebnis der Auswahl ausgeleitet wird (Zeile 3 und 4). Die Kombination von Emblem-ID und Permalink der Pictura wird verwendet, um möglichen Fehlern bei der Vergabe der Emblem-ID zu begegnen.

Um den auswählenden Ausdruck dynamisch zu berechnen, wird die Auswahl der Erschließungselemente durch einen p:filter-Schritt vorgenommen (Zeile 9-18). Der auswählende mit XPath-Ausdruck wird mit String-Operatoren aus den übergebenen Parametern zusammengesetzt. Ein- und Ausgabeport dieses Schrittes sind implizit mit dem primären Eingabe- bzw. Ausgabeport verbunden.

<p:declare-step type="emblem:select-iconclass">   <p:input  port="source"/>   <p:output port="result" sequence="true"/>   <p:option name="emblemId" required="true"/>   <p:option name="imageUri" required="true"/>   <p:filter>     <p:with-option name="select"                    select="concat(                      '//emblem:emblem[substring(@globalID, 44) = "',                      $emblemId,                      '"]/emblem:pictura[@xlink:href = "',                      $imageUri,                      '"]/emblem:iconclass'                    )"/>   </p:filter> </p:declare-step> Auswahl der emblem:iconclass-Elemente

Die Hauptverarbeitung liest die Erschließungsdaten vom primären Eingabeport source (Zeile 7) und besitzt keinen Ausgabeport. Sie iteriert über jedes in den Erschließungsdaten enthaltene Emblembuch (Zeile 11 und 12) und lädt die zugehörigen Strukturdaten (Zeile 13 bis 19).

Nun wechselt der Fokus zum geladenen Strukturdatendokument. Ein Auswahlfenster p:viewport wandert über jeden eine bildliche Darstellung repräsentierenden Abschnitt (Zeile 19). Emblem-ID und Permalink der Seite werden berechnet (Zeile 20 und 21) und dem Auswahlschritt übergeben (Zeile 22 bis 28). Der primäre Eingabeport dieses Schrittes wird mit dem primären Eingabeport der Hauptverarbeitung verbunden.

Das Ergebnis des Auswahlschrittes wird als Kind des im Auswahlfenster befindlichen Abschnitts ergänzt (Zeile 29 bis 36). Dazu wird der primäre Eingabeport des Einfügungsschrittes mit dem aktuellen Auswahlfenster (Zeile 30 bis 32) und der die Einfügung aufnehmende sekundäre Eingabeport des Einfügungsschritts mit dem primären Ausgabeport des Auswahlschritts verbunden (Zeile 33 bis 35).

Sind alle bildlichen Darstellungen des geladenen Strukturdatendokuments bearbeitet, dann werden mit einer XSL-Transformation die emblem:iconclass-Elemente in die vorgeschriebenen TEI-Strukturen umgewandelt (Zeile 38 bis 45). Bevor das geladene Strukturdatendokument auf den Datenträger geschrieben wird (Zeile 54 bis 56), wird in einer weiteren Transformation ein Angabe über die vorgenommene Änderung ergänzt (Zeile 46 bis 53).

<p:declare-step name="main" version="1.0"                 xmlns:emblem="http://diglib.hab.de/rules/schema/emblem"                 xmlns:xlink="http://www.w3.org/1999/xlink"                 xmlns:tei="http://www.tei-c.org/ns/1.0"                 xmlns:p="http://www.w3.org/ns/xproc">    <p:input  port="source" primary="true"/>    <p:declare-step type="emblem:select-iconclass">…</p>    <p:for-each>      <p:iteration-source select="//emblem:biblioDesc"/>      <p:variable name="objectUri" select="substring-before((emblem:biblioDesc//@xlink:href)[1], '?')"/>      <p:variable name="structUri" select="concat(…)"/>      <p:variable name="filename"  select="tokenize($objectUri, '/')[5]"/>      <p:load>        <p:with-option name="href" select="$structUri"/>      </p:load>      <p:viewport match="tei:div[@type = 'emblem_pictura']" name="pictura">        <p:variable name="emblemId" select="tei:div/@n"/>        <p:variable name="imageUri" select="concat(…)"/>        <emblem:select-iconclass name="select-iconclass">          <p:with-option name="emblemId" select="$emblemId"/>          <p:with-option name="imageUri" select="$imageUri"/>          <p:input port="source">            <p:pipe step="main" port="source"/>          </p:input>        </emblem:select-iconclass>        <p:insert position="last-child" match="tei:p">          <p:input port="source">            <p:pipe step="pictura" port="current"/>          </p:input>          <p:input port="insertion">            <p:pipe step="select-iconclass" port="result"/>          </p:input>        </p:insert>      </p:viewport>      <p:xslt>        <p:input port="stylesheet">          <p:document href="../xslt/emblem-to-tei.xsl"/>        </p:input>        <p:input port="parameters">          <p:empty/>        </p:input>      </p:xslt>      <p:xslt>        <p:input port="stylesheet">          <p:document href="../xslt/mark-tei-revision.xsl"/>        </p:input>        <p:input port="parameters">          <p:empty/>        </p:input>      </p:xslt>      <p:store method="xml" omit-xml-declaration="true">        <p:with-option name="href" select="concat('file:/s:/drucke/', $filename, '/tei-struct.xml')"/>      </p:store>    </p:for-each> </p:declare-step> Hauptverarbeitung

Fazit

Die in der Hauptverarbeitung definierte Prozessierungspipeline wurde mit XML Calabash ausgeführt und auf die von Foto Marburg zur Verfügung gestellten Erschließungsdaten angewendet. Dadurch konnten 24.195 ICONCLASS-Notationen für 5.011 Embleme in 56 Emblembüchern in die Wolfenbütteler Digitale Bibliothek übertragen werden. Mit XProc und XSLT standen XML-Technologien zur Verfügung, mit denen sich die notwendigen Verarbeitungsschritte maschinenunabhängig als Manipulation von XML-Bäumen ausdrücken und durch einen quelloffenen XProc-Prozessor ausführen ließen.

TEI-Revision einfügen oder ergänzen

Üblicherweise bearbeite ich mehrere dutzend XML-Dateien gleichzeitig, um Kodierungen anzupassen oder Fremddaten einzupflegen. Damit auch nachvollziehbar bleibt, wer wann was an den Dokumenten geändert hat, füge ich immer einen Änderungsvermerk ein. Da das bei einer größeren Menge an Dokumenten nicht per Hand passieren kann, verwende ich folgende XSL-Transformation, die ich für den jeweiligen Fall einfach anpasse.

<xsl:transform version="2.0"                exclude-result-prefixes="#all"                xpath-default-namespace="http://www.tei-c.org/ns/1.0"                xmlns="http://www.tei-c.org/ns/1.0"                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">   <xsl:template match="node() | @*">     <xsl:copy>       <xsl:apply-templates select="node() | @*"/>     </xsl:copy>   </xsl:template>   <xsl:template match="teiHeader[not(revisionDesc)]">     <xsl:copy>       <xsl:apply-templates select="node() | @*"/>       <revisionDesc status="published">         <xsl:call-template  name="insert-change"/>       </revisionDesc>     </xsl:copy>   </xsl:template>   <xsl:template match="revisionDesc">     <xsl:copy>       <xsl:apply-templates select="node() | @*"/>       <xsl:call-template  name="insert-change"/>     </xsl:copy>   </xsl:template>   <xsl:template name="insert-change">     <change when="{format-date(current-date(), '[Y0001]-[M01]-[D01]')}" who="mailto:maus@hab.de">       Iconclass-Erschließung aus Foto Marburg eingefügt; Projekt Emblematica Online - Linked Open Emblem Data.     </change>   </xsl:template> </xsl:transform>

Das erste Template implementiert eine Identitätstransformation, in der rekursiv alle Knoten in den Ergebnisbaum kopiert werden.

Das zweite Template verarbeitet Dokumente, die noch keine revisionDesc enthalten. Alle Knoten des teiHeader werden kopiert, dann wird eine revisionDesc mit dem Änderungsvermerk am Ende eingefügt.

Das tritte Template verarbeitet eine existierende revisionDesc. Der Inhalt wird kopiert und ein neuer Änderungsvermerk wird ergänzt.

Das vierte Template wird von den Templates zwei und drei aufgerufen und erzeugt den datierten Änderungsvermerk.

Today I Learned: Mengenoperatoren in XPath 2.0

XPath 2.0 führt die Operatoren union, intersect und except ein, mit denen die Vereinungs-, Schnitt- bzw. Differenzmenge berechnet werden können. Diese Operatoren gelten aber nur für Knotenmengen.

Für den Vergleich von Mengen atomischer Werte (Zeichenketten usw.) listet Kay 2008, S. 631 Kay, Michael. XSLT 2.0 and XPath 2.0, 4th Edition. Indianapolis, IN: Wiley Publishing, 2008. die entsprechenden Äquivalente:

Vereinigungsmenge
distinct-values($A, $B)
Schnittmenge
distinct-values($A[. = $B])
Differenzmenge
distinct-values($A[not(. = $B)])

Kay 2008 (ebd.) führt auch die in XPath 1.0 möglichen Ausdrücke auf, um die Schnitt- bzw. Differenzmenge von Knotenmengen zu berechnen.

Schnittmenge
$A[count(. | $B) = count($B)]
Lies: Alle Elemente von $A für die gilt, dass die Vereinigungsmenge des Elements mit der Menge $B die selbe Anzahl an Knoten enthält wie die Menge $B; das Element also in $B enthalten ist.
Differenzmenge
$A[count(. | $B) != count($B)]

Today I Learned: Schematron in RelaxNG/Compact einbetten

Die Syntax für Annotationen in der kompakten Syntax von RelaxNG ist etwas gewöhnungsbedürftig, erlaubt aber das Einbinden von Schematron-Regeln, mit denen weitergehende Restriktionen geprüft werden können.

internalEntity =   [      s:pattern [         s:rule [            context = "*[@rdf:about]" s:assert [               test = "matches(@rdf:about, '^http://([^.]+\.)?hab\.de')"               "Verwende <owl:sameAs> für Statements zu Entitäten, die nicht unter der Kontrolle der HAB liegen."            ]         ]      ]   ]   attribute rdf:about { xsd:anyURI }   & Label+

Im Kopf der Grammatik müssen die Schematron-Namensraumbindungen vorgenommen werden, da trang sie nicht automatisch ergänzt.

[    s:ns [ prefix = "rdf" uri = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" ]    s:ns [ prefix = "owl" uri = "http://www.w3.org/2002/07/owl#" ] ]

Und merke:

  • <oXygen/> 18.1 validiert integrierter Schematron-Regeln nur in der XML-Syntax
  • Emacs' rnc-mode rückt die einer Annotation folgenden Definitionen nicht richtig ein

Darstellung von Planetensymbolen in der Edition des Diariums von Herzog August dem Jüngeren

In der Digitalen Edition des Diariums von Herzog August dem Jüngeren sollen die für die Wochentage verwendeten Planetensymbole in der Onlinepublikation dargestellt werden. Die für die Anzeige verwendete Schriftart Junicode definiert allerdings keine Glyphen für die betreffenden Zeichen. Ob und wie die Planetensymbole dargestellt werden, wird damit vom Browser abhängig. Ein aktueller Firefox unter Windows verwendet zum Beispiel eine Schriftart, in der es keine fett geschnittenen Glyphen für die Zeichen U+2642 und U+2640 gibt. Der Browser fällt in diesem Fall auf den regulären Schnitt zurück, wodurch die Darstellung der Symbole uneinheitlich wirkt.

Screenshot Planetensymbole in Firefox 38

Um eine einheitliche Darstellung der Symbole zu erreichen werden die Glyphen der betreffenden Zeichen aus einer anderen Schriftart entnommen. Als Schriftart wird die von George Douros erstellte Schriftart Symbola ausgewählt. Sie ist frei verfügbar und enthält sowohl fett als auch regulär geschnittene Planetensymbole.

Da nur ein Bruchteil der in der Schriftart definierten Zeichen benötigt wird und die Schriftart mit ca. 1.1 Megabyte verhältnismäßig groß ist, wird als erstes eine Schriftartendatei erzeugt, die nur Glyphen des Unicodeblocks Miscellaneous Symbols (U+2600–U+26FF) enthält.

dmaus@x220i ~ pyftsubset Symbola.ttf --unicodes=2600-26FF --output-file=Symbola-26xx.ttf

Die so erstellte Schriftartendatei wird anschließend in das für Webschriftarten übliche WOFF-Format konvertiert.

dmaus@x220i ~ cat > metadata.xml <metadata version="1.0">   <credits>     <credit name="George Douros" url="http://users.teilar.gr/~g1951d/" role="creator"/>   </credits>   <description>     This font is a subset of the complete Symbola font. It only contains glyphs from the Unicode block     Miscellaneous Symbols, range U+2600-26FF.   </description> </metadata>^D dmaus@x220i ~ sfnt2woff -m metadata.xml Symbola-26xx.ttf

Ideal wäre es, wenn der Browser die Schriftart nur für die Zeichen aus Block Miscellaneous Symbols verwendet. Die aktuelle CSS-Spezifikation der Schriftartenunterstützung, CSS Fonts Module Level 3, behandelt dieses Anwendungsszenario in Abschnitt 4.6 unter der Überschrift "Using character ranges to define composite fonts". Dort wird es wie folgt beschrieben:

Multiple @font-face rules with different unicode ranges for the same family and style descriptor values can be used to create composite fonts that mix the glyphs from different fonts for different scripts. This can be used to combine fonts that only contain glyphs for a single script (e.g. Latin, Greek, Cyrillic) or it can be used by authors as a way of segmenting a font into fonts for commonly used characters and less frequently used characters. Since the user agent will only pull down the fonts it needs this helps reduce page bandwidth.

If the unicode ranges overlap for a set of @font-face rules with the same family and style descriptor values, the rules are ordered in the reverse order they were defined; the last rule defined is the first to be checked for a given character.

Allerdings: Die für das Zusammensetzen von Schriftarten verwendete CSS-Eigenschaft unicode-range wird nicht von allen Browsern unterstützt. Insbesondere Firefox beachtetet diese Angaben standardmäßig erst seit Version 44, zuvor mussten sie ausdrücklich in den Experteneinstellungen eingeschaltet werden. Um größtmögliche Kompatibilität zu gewährleisten, wird die Schriftart daher über eine CSS-Klasse zugewiesen.

@font-face {   font-family: Symbole;   src: url(http://diglib.hab.de/rules/fonts/Symbola-26xx.woff) format("woff"); } .symbol {   font-family: Symbole; } <span class="symbol" title="Mittwoch">☿</span>

Und voilà: Die Planetensymbole werden einheitlich dargestellt.

Screenshot Planetensymbole in Schriftart Symbola

Today I Learned: The different uses of <p:input> in XProc 1.0

Update 2017-09-16: Turns out that I am not the only one who struggles a little bit, compared to the rest of XProc with using one and the same name for different things. After a short discussion in Aachen we agreed to rename p:input to p:with-input when it is used as document input port connection.

XProc 1.0 uses p:input for three distinct purposes:

  1. to declare the document input ports of a step
  2. to declare the parameter input ports of a step
  3. to connect document input ports of a declared step

The following examples illustrate the distinction between a document input port declaration and a document input port connection.

<p:declare-step version="1.0" xmlns:p="http://www.w3.org/ns/xproc">   <p:sink>     <p:input port="source">       <p:inline>         <foobar/>       </p:inline>     </p:input>   </p:sink> </p:declare-step>

The pipeline has a single step p:sink whose source input port is connected to a p:inline that provides an inline document. The p:input acts as a document input port connection.

<p:declare-step version="1.0" name="main" xmlns:p="http://www.w3.org/ns/xproc">   <p:input port="source">     <p:inline>       <foobar/>     </p:inline>   </p:input>   <p:sink>     <p:input port="source">       <p:pipe step="main" port="source"/>     </p:input>   </p:sink> </p:declare-step>

Here we have two p:input elements. The first is a document input port declaration with a default connection to an inline document provider. The second input is a document input port connection and connects the source input port of the p:sink to the pipeline's declared input port, i.e. the first p:input. Observe that this required the pipeline to have a name to specify the connection target in p:pipe.

One practical difference between the two is, that the inlined document is fixed in the first case, while it can be overridden in the second. It might also be worth noting that there are two other pipeline elements that as document input port connection, p:iteration-source and p:viewport-source.

Sarsaparilla

Sarsaparilla

Today I Learned: The second argument to document() (XSLT 1.0)

When accessing documents with document() I can provide a node set as second argument. If the first argument is a relative URI reference, then the base URL of the first node of this node set is used to resolve it. Otherwise the processor uses the stylesheet's base URL if the first argument is a string or the first argument's base URL if it is a node.

In the diary of Augustus the Younger we annotate places and persons with a reference to a central registry file. The registry contains a link to an authority record and a standardized name of the entity.

<div xml:id="E1601-04-03">   <head>     <date when="1601-04-03">den 3 Aprilis <c eg:style="display: inline">♀</c> </date>   </head>   <p>     H<ex>err</ex> <rs ref="register.xml#Julius_Ernst_Br-Db" type="person">Juli<ex>us</ex>     kommen</rs>; die Pfe<ex>rde</ex> nach <rs ref="register.xml#Warpke" type="place"">warpke</rs>     geschickett.   </p> </div>

And in the registry file:

<person xml:id="Julius_Ernst_Br-Db">   <idno type="URI">http://d-nb.info/gnd/121123553</idno>   <persName type="display">Julius Ernst, Braunschweig-Lüneburg, Herzog</persName> </person>

I wanted the name to be displayed to the user once the mouse pointer hovers over the reference. I knew that I had to dereference the value of the ref attribute and put the display name in a HTML title attribute. I did not know to which base URL relative URI references are resolved: the stylesheet's, the documents', or maybe even the processor's current working directory.

Reading up on this in my trustworthy Kay (Kay, Michael. XSLT: Programmer’s Reference. Birmingham: Wrox Press, 2000) I got the whole story. If document() is called with one argument and the argument is a string, the stylesheet's base URL is used to resolve a relative URI reference. If the argument is a node, the node's base URL is used. Use the second argument to provide a node whose base URL should be used instead.

For me this meant: Simply use document(ref) without worries, since the relative URI reference is resolved with the ref attribute's base URI.

Im Nachgang zur XML Prague 2017: Schematron

Still und leise wurde bereits Anfang 2016 der ISO-Standard ISO-19757-3 aka ISO Schematron aktualisiert. Auf dem Schematron Users Meetup wurden die wesentlichen Neuerungen kurz umrissen. Neben der expliziten (normativen) Definition der Abfragesprache XSLT2 wurden die Möglichkeiten verbessert, menschen- und maschinenlesbare Berichte zu erstellen. Für komplexere Validierungsszenarien können nun im pattern-Element innerhalb eines documents-Attribut IRIs der Dokumente angegeben werden, für die in der pattern definierten Regeln geprüft werden.

Von praktischem Interesse für größere Editionsprojekte dürfte das von Nico Kutscherauer entwickelte Schematron Quickfix (SQF) sein. SQF ist eine in Schematron eingebettete Sprache, mit der interaktive Korrekturmöglichkeiten für Validierungsfehler beschrieben werden. Mit Hilfe von XML-Editoren wie <oXygen/>, die SQF nativ unterstützen, könnte die Dateneingabe oder Datenkorrektur bequemer gestaltet werden, wenn Bearbeiter eine Fehlerkorrektur auf Knopfdruck veranlassen können. Einrichtung und Anwendung von SQF setzt allerdings qualifiziertes Personal in angemessenen Umfang voraus, lohnte sich daher erst in größeren Projekten.

Zu guter Letzt wurde noch wichtige Aufklärungsarbeit über das Schemtron-Maskottchen geleistet. Es ist nicht etwa ein Hase oder Kaninchen, sondern eine Mischung aus einem Bilby und einem Bettong, zwei australischen Beuteltieren.

Folien Werkstattgespräch 15. Dezember 2016

Meine Folien vom Werkstattgespräch zum Wolfenbütteler Katalog der Lutherdrucke nun auch online. Die Folien sind mit Eric Meyers exzellentem Simple Standards-Based Slide Show System (S5) herstellt. Die Navigation erfolgt mit Hilfe der Cursor-Tasten.

FYI: Calling Bullshit, A course to teach you how to think critically

callingbullshit.org

The world is awash in bullshit. Politicians are unconstrained by facts. Science is conducted by press release. So-called higher education often rewards bullshit over analytic thought. Startup culture has elevated bullshit to high art. Advertisers wink conspiratorially and invite us to join them in seeing through all the bullshit, then take advantage of our lowered guard to bombard us with second-order bullshit. The majority of administrative activity, whether in private business or the public sphere, often seems to be little more than a sophisticated exercise in the combinatorial reassembly of bullshit.

Our aim in this course is to teach you how to think critically about the data and models that constitute evidence in the social and natural sciences.

  • Carl T. Bergstrom, UW Department of Biology
  • Jevin West, UW Information School

Welche Möglichkeiten gibt es, ein XML Dokument mit einem Schema zu verknüpfen?

Wenn es um das Validieren von XML-Dokumenten geht, gibt es nicht nur verschiedene Schematechnologien, sondern auch verschiedene Mechanismen, ein einzelnes XML-Dokument (Dokumentinstanz) mit Schemadateien zu verknüpfen.

Die untenstehenden Mechanismen beruhen alle darauf, die Verknüpfung eines Dokumentes mit einem oder mehreren Schemata im jeweiligen Dokument festzuhalten. Das ist für sich genommen weder gut noch schlecht, allerdings auch nicht die einzige und nicht immer die beste Variante. Der grundsätzliche Nachteil liegt darin, dass die Verknüpfung zwischen Dokumentinstanz und Schemadatei Teil der Dokumentinstanz ist und eine Änderung der Verknüpfung eine Änderung der Dokumentinstanz erforderlich macht. Eine Änderung der Verknüpfung kann aus verschiedenen Gründen erfolgen:

  • der Ablageort der Schemadatei ändert sich
  • der Name der Schemadatei ändert sich
  • eine andere Schematechnologie muss verwendet werden
  • eine andere Schematechnologie soll ergänzend verwendet werden

Während eine Anpassung der Dokumentinstanz bei einem, zwei oder vielleicht auch noch zehn Dokumenten halbwegs handhabbar ist, wird die Sache bei mehreren dutzend oder gar hunderten von XML-Dokumenten zu einer echten Herausforderung.

Hinzu kommt, dass nur die Verknüpfung über xml-model sowohl die gleichzeitige Verwendung verschiedener Schemadateien, als auch die gleichzeitige Verwendung verschiedener Schematechnologien erlaubt. Die Verwendung der Document Type Declaration ebenso wie die Verwendung der Schema Locating Hints bindet an die jeweils unterstützte Technologie.

Lange Rede, kurzer Sinn: Wenn ich die Verknüpfung von Dokumentinstanz und Schema in das Dokument einbetten muss, dann bevorzuge ich xml-model, weil sie mir die größte Flexibilität hinsichtlich der Schematechnologien lässt. Wenn ich es frei entscheiden kann, dann definiere ich die Verknüpfung außerhalb der Dokumentinstanz.

Document Type Declaration

Schematechnologien
  • Document Type Definition
Mehrere Schemadateien
Nein
Beispiel
<!DOCTYPE TEI SYSTEM "http://example.com/tei-transcript.dtd">
Literatur

Schema Locating Hints

Schematechnologien
  • W3C XML Schema
Mehrere Schemadateien
Bedingt
Anmerkung
Die Schema Locating Hints verknüpfen je einen XML Namensraum mit je einem Schema.
Beispiel
<TEI xmlns="http://www.tei-c.org/ns/1.0"      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"      xsi:schemaLocation="http://www.tei-c.org/ns/1.0 http://example.com/tei-transcript.xsd">   … </TEI>
Literatur

xml-model Processing Instruction

Schematechnologien
  • Document Type Defintion
  • W3C XML Schema
  • RelaxNG
  • Schematron
  • ...
Mehrere Schemadateien
Ja
Beispiel
<?xml-model href="http://example.com/tei-transcript.rnc" type="application/relax-ng-compact-syntax"?> <?xml-model href="http://example.com/tei-transcript.sch" schematypens="http://purl.oclc.org/dsdl/schematron"?>
Literatur

Schritte gruppieren mit <p:group>

p:group ist ein zusammengesetzer Schritt (compound step) mit dessen Hilfe sich andere Schritte zu einer Subpipeline zusammenfassen lassen. Innerhalb von p:group können Ausgabeports definiert werden, mit denen (Zwischen-)Ergebnisse der Subpipeline nach außen geleitet werden können.

<p:group name="subpipeline" xmlns:p="http://www.w3.org/ns/xproc">   <p:output port="result">     <p:pipe step="last-step" port="result"/>   </p:output>   <p:output port="other">     <p:pipe step="intermediate-step" port="result"/>   </p:output> </p:group>

Qualifizierte und unqualifizierte Attribute in XML Schema

Im Rahmen des Projektes Linked Open Emblem Data nehme ich gerade das für Emblembuchbeschreibungen verwendete Emblem Schema unter die Lupe. Um einen Eindruck davon zu bekommen, wie eine Emblembuchbeschreibung aussieht, die von allen Optionen des Schemas gebraucht macht, habe ich mit Hilfe von <oXygen/> ein Beispieldokument auf Basis des Schemas erstellen lassen. Zu meinem Erstaunen enthielt das Beispieldokument ein einzelnes, mit dem Namensraum des Emblem Schemas qualifiziertes Attribut.

Screenshot des Beispieldokuments

Stellt sich heraus, dass die Regel für den Namensraum von Attributdefinitionen sich danach unterscheiden, wo ein Attribut deklariert wird. Wird es direkt als Kindelement des schema-Elements als sogenanntes "globales Attribut" deklariert, dann wird immer der im targetNamespace-Attribut des Schemas angegebenen Namensraum verwendet. In allen anderen Fällen kann mit Hilfe des Attributs form angegeben werden, ob es qualified, also mit, oder unqualified und damit ohne Namensraum definiert ist. Wird das Attribut form weggelassen, dann entscheidet der im Attribut attributeFormDefault des Wurzelelements angebene Wert.

Das heisst, dass in folgendem Schema das Attribut byReferenceQualified mit, das Attribute byReference jedoch ohne Namensraum definiert ist:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.org/"            elementFormDefault="qualified" attributeFormDefault="unqualified"            targetNamespace="http://example.org/">   <xs:element name="root">     <xs:complexType>       <xs:attribute ref="byReferenceQualified"/>       <xs:attributeGroup ref="byReference"/>     </xs:complexType>   </xs:element>   <xs:attribute name="byReferenceQualified"/>   <xs:attributeGroup name="byReference">     <xs:attribute name="byReference"/>   </xs:attributeGroup> </xs:schema>

Und siehe da: Im Emblem Schema ist genau das der Fall.

Screenshot der Attributdeklaration im Emblem Schema 1.2

Das fragliche Attribut key wird in die Attributgruppe standardAttrib über eine Referenz auf die globale Attributdeklaration eingebunden, während die anderen Attribute entweder von Haus aus qualifiziert sind (xml:id, xml:lang, xlink:href) oder direkt in der Attributgruppe deklariert werden (page). Umgekehrt heisst das aber auch, dass keines der anderen global deklarierten Attribute im Schema verwendet wird.