Hallo XSLT 3.0
David Maus, 29. Mär 2018
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 2008, 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.