Webengineering_Roethig/Kapitel/09_XML.tex

441 lines
21 KiB
TeX

\chapter{XML -- \acl{XML}}\index{XML}
\acf{XML}:
\begin{itemize}
\item Vorgaben für die Grammatk einer Sprache
\item Tags mit Attributen und Inhalten
\item jede \acs{XML}-Datei muss/sollte wohlgeformt und gültig sein!
\textit{Wohlgeformtheit:}
\begin{itemize}[noitemsep]
\item Tags immer paarweise, \dash zu jedem Start-Tag gibt es das passende End-Tag
\item korrekte Schachtelung der Tags, \dash das zuletzt geöffnete und noch nicht geschlossene Tag muss als erstes geschlossen werden.
\item Es gibt genau einen \enquote{Wurzeltag}/\enquote{root-Tag}, \dash genau ein Tag auf oberster Ebene welches das gesamte restliche Dokument enthält.
\item[$\Rightarrow$] Kann ohne Kenntnis der konkreten Sprache geprüft werden!
\end{itemize}
\textit{Gültigkeit:}
\begin{itemize}[noitemsep]
\item evtl. Name des Wurzelelements
\item Elementnamen
\item Enthaltenseinsmodell für jedes Element (möglicher Inhalt eines Tags)
\item Attributnamen
\item Zugehörigkeit von Attributen zu Tags
\item Attributtyp (mögliche Attributwerte)
\item[$\Rightarrow$] Beschreibung der konkreten Grammatik
\end{itemize}
Gültigkeit kann anhand einer \acs{DTD} geprüft werden. Eine Alternative dazu ist \acf{XSD} (deutlich mehr Möglichkeiten für Inhaltsmodell und Typisierung, jedoch viel komplexer).
\end{itemize}
\section{DTD}\index{DTD}
Die \acf{DTD} \ldots
\begin{itemize}[noitemsep]
\item[\ldots] wird referenziert in einer (vollständigen) \code{DOCTYPE}-Deklaration.
\item[\ldots] ist textbasiert, aber nicht \acs{XML}-basiert
\item[\ldots] besteht aus einer Folge von (also beliebig vielen) Deklarationen (siehe \autoref{lst:xml_deklaration}) in der Variante der \code{DOCTYPE}-Deklaration
\end{itemize}
\medskip
\begin{lstlisting}[label=lst:xml_deklaration,language=HTML5,caption=DOCTYPE- und XML-Deklaration]
<!DOCTYPE root_element ... mit Param. als Aufzählung der Werte in bestimmter Reihenfolge>
<?xml ... mit Parametern als Parname="Parwert" ?>
\end{lstlisting}
Für unsere Zwecke reichen zwei Deklarationen: \code{<!ELEMENT \ldots>} und \code{<!ATTLIST \ldots>}
Eine \acs{DTD} wird wie folgend aufgebaut:
\subsection{\code{ELEMENT}}
Beschreibt ein Element und seinen Inhalt.
\bigskip
\begin{lstlisting}[language=XML,caption=DTD - ELEMENT]
<!ELEMENT tagname inhaltsmodell>
\end{lstlisting}
\begin{description}
\item[\code{tagname}] Name des Tags oder Elements, bestehend aus Buchstaben (Groß- und Kleinschreibung, case-sensitive), Ziffern, manchen Sonderzeichen (\zB Unterstrich/\enquote{\_}), beginnend nur mit Buchstabe oder Unterstrich.
Theoretisch kann der \code{tagname} eine beliebige Länge haben, sollte aber aus praktischen Gründen auf <\,256 Zeichen beschränkt werden. Zudem sollten keine Umlaute und sonstige nationale Sonderzeichen verwendet werden.
\item[\code{inhaltsmodell}] Dies kann sein: \hfill
\begin{description}
\item[\code{EMPTY}] Leeres Inhaltsmodell, \dash der Tag enthält immer genau nichts. \newline
Beispiel: \code{<!ELEMENT br EMPTY>} für einen Zeilenumbruch in HTML.
\item[\code{ANY}] Beliebiger Inhalt, \dash beliebige Mischung aus Text und Tags (welche aber in der \acs{DTD} deklariert sein müssen). Es gibt kein Beispiel in HTML (und jeder anderen dem Vorleser bekannten Grammatik). $\Rightarrow$ vor dem Inhaltsmodell \enquote{\code{ANY}} warnt der Vorleser!
\item[(\code{\#PCDATA})] \enquote{Parsed Character Data} \newline
Zeichenfolgen, welche keine Tag-ähnlichen Strukturen enthalten (\zB \enquote{<} mit \code{\&lt;} umschreiben).\newline
Beispiel: \code{<!ELEMENT title (\#PCDATA) >}
\item[sequenz] \code{(tagname1, tagname2[, tagname3\ldots])}\newline
Inhalt sind die aufgelisteten Tags (in genau dieser Reihenfolge).
Beispiel: \code{<!ELEMENT html (head, body) >}
\item[auswahl] \code{(tagname1|tagname2[|tagname3\ldots])}\newline
Inhalt ist entweder \code{tagname1} oder \code{tagname2} oder \ldots Es können auch Sequenzen angegeben werden.\newline
Beispiel (aus früherem HTML): \code{<!ELEMENT html ((head,body)|frameset)}
\item[gemischt] \code{(\#PCDATA|tagname1[|tagname2\ldots])}\newline
Inhalt ist entweder Text oder \code{tagname1} oder \code{tagname2} \ldots \newline
Hinweis: Statt \code{tagname} sind auch weitere Inhaltsmodelle (sequenz, auswahl) möglich!
\end{description}
\end{description}
\begin{description}
\item[Häufigkeitsindikatoren]\hfill\newline
Nachgestelltes Symbol, mit dem ein Inhaltsmodell in der Häufigkeit seines Auftretens beeinflusst werden kann.
\begin{tabular}{cl}
\code{\textbf{*}} & Beliebig viele (inkl. keinmal) \\
\code{\textbf{+}} & Beliebig viele, aber mindestens einmal\\
\code{\textbf{?}} & Einmal oder keinmal (\enquote{optional})\\
\end{tabular}
Beispiel:
\begin{itemize}[noitemsep]
\item \code{<!ELEMENT p (\#PCDATA|em|a|span|\ldots)* >}
\item \code{<!ELEMENT ul li+ >}
\item \code{<!ELEMENT dl (dt|dd)+ >}
\end{itemize}
\end{description}
\subsection{\code{ATTLIST}}
Beschreibt die Attribute eines Elements.
\bigskip
\begin{lstlisting}[language=XML,caption=DTD -- ATTLIST]
<!ATTLIST tagname attrname attrtyp voreinstellung>
|______ auch mehrfach ______|
\end{lstlisting}
\begin{description}
\item[\code{tagname}] Der Tag, für welche die Attribute deklariert werden
\item[\code{attrname}] Name des Attributs (derselbe Aufbau und dieselben Einschränkungen wie für \code{tagname})
\item[\code{attrtyp}] \hfill
\begin{description}
\item[\code{CDATA}] (Character Data), \dash beliebige Zeichenfolge (inkl. Tag-ähnlichen Strukturen, welche hier einfache Zeichenfolgen darstellen. Doppelte Hochkommata müssen mit \html{&quot;} umschrieben werden.
\textit{Beispiel}: \xml{<!ATTLIST img alt CDATA #REQUIRED>}
\item[\code{ID}] \label{xml:attrtyp:id} Dokumentenweit eindeutiger Attributwert, Aufbau/Zusammensetzung wie ein \code{tagname} (es ist kein rein numerischer Wert möglich).
\textit{Beispiel}: \xml{<!ATTLIST a id ID #IMPLIED>}
\item[\code{IDREF}, \code{IDREFS}] Ein Attributwert vom Typ ID, potentiell mehrere Attributwerte vom Typ \hyperref[xml:attrtyp:id]{ID} (durch Leerzeichen getrennt).
\textit{Beispiel} aus \acs{HTML}: Bei Formularen, nicht jedoch bei \html{<a href="">}
\item[\code{NMTOKEN}, \code{NMTOKENS}] \enquote{Nametoken}
Aufbau ähnlich wie \code{tagname}, aber jedes der erlaubten Zeichen kann erstes Zeichen sein! So kann \code{123abc} kein Tagname sein, da Tags nicht mit einer Zahl anfangen dürfen, ein \code{NMTOKEN} jedoch schon!\newline
Durch Leerzeichen werden mehrere \code{NMTOKEN} voneinander getrennt.
\textit{Beispiel} aus \acs{HTML}: \xml{<!ATTLIST div class NMTOKENS #IMPLIED>}
\item[Aufzählung] \code{nmtoken1|nmtoken2[|nmtoken3\ldots]}\newline
Aufzählung aller möglichen Werten vom Typ Nametoken
\end{description}
\item[Voreinstellung] \hfill
\begin{description}
\item[\code{"\textit{value}"}] Ein vorgegebener Standardwert vom selben Typ wie \code{attrtyp}.
\item[\code{\#IMPLIED}] Gibt an, dass das Attribut optional ist.
\item[\code{\#REQUIRED}] Gibt an, dass das Attribut Pflicht ist.
\item[\code{\#FIXED "\textit{val}"}]
Wenn das Attribut gesetzt wird, darf es nur den Wert \code{val} annehmen.
\textit{Beispiel} aus \acs{HTML}: \xml{<!ATTLIST video autoplay #FIXED "autoplay">}
Hinweis: Manche Attributtypen, wie \zB \hyperref[xml:attrtyp:id]{ID}, können nur die Voreinstellung \newline
\phantom{Hinweis:} \code{\#IMPLIED} oder \code{\#REQUIRED} besitzen.
\end{description}
\item[weitere Attributtypen] \hfill
\begin{itemize}[noitemsep]
\item \code{ENTITY}, \code{ENTITIES}
\item \code{NOTATION}
\end{itemize}
\end{description}
\newpage
\section{Was ist XSLT?}\index{XSLT}
\acf{XSLT} ist Teil der \acf{XSL}-Spezifikation.
\begin{description}
\item[\acs{XSLT}] Eine Sprache zur Umsetzung von \acs{XML} basierten Dokumenten in andere (meist ebenfalls \acs{XML}-basierte) Dokumente.
\item[\acf{XPath}] Sprache zur Selektion von Knotenmengen) aus einem \acs{XML}-Dokument
\item[XML-FO] Konkrete \acs{XML}-basierte Sprache zur designgetreuen Ausgabe von Dokumenten.
\end{description}
Wer führt die Transformation durch?
\begin{itemize}[noitemsep]
\item ein Standalone-Tool:
\begin{itemize}[noitemsep]
\item \acs{XSL} Transformator (Kommandozeilenaufruf: \code{xslt})
\item xalan
\item saxon (auch für Version 2, kommerziell)
\end{itemize}
\item Server-Side:
\begin{itemize}[noitemsep]
\item Apache-Projekt Cocoon
\item Perl-Modul: AxKit
\end{itemize}
\item Client-Side:
\begin{itemize}[noitemsep]
\item gängige WebBrowser (Chrome, Firefox, Edge, Safari, \ldots)
\end{itemize}
\end{itemize}
Die \acs{XSLT}-Sprache ist \acs{XML}-basiert . \autoref{lst:xslt_beispiel} zeigt ein Beispiel.
\medskip
\begin{lstlisting}[language=XML,caption=XSLT -- Aufbau,label=lst:xslt_beispiel]
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="Namespace der Zielsprache">
<xsl:output method="xml|text|html" encoding="KodierungZielformat"
doctype-public="Public-Id für DOCTYPE-Dekl."
doctype-system="System-ID für DOCTYPE-Dekl." />
<!-- Liste von Transformationsvorschriften/Templates -->
</xsl:stylesheet>
\end{lstlisting}
\begin{Tipp}[frametitle=Editorempfehlung von Herrn Röthig]
Editix als FreeEditix. Erhältlich auf: \url{http://editix.com/}
\end{Tipp}
Wie die Verknüpfung einer \acs{XSLT} mit einem \acs{XML}-Dokument aussieht, zeigt \autoref{lst:xml_xslt} auf Seite~\pageref{lst:xml_xslt}.
Mit \xml{<?xml-stylesheet href="..." ?>} (Bindestrich, kein Doppelpunkt) wird die XSLT aufgerufen.
\newpage
\begin{lstlisting}[language=XML,caption={Abstraktes XML-Dokument für die Verknüpfung mit XSLT},label=lst:xml_xslt]
<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet type="text/xsl" href="url/zur/Transformdatei.xsl" ?>
<!DOCTYPE bla SYSTEM "http://ref.zur/DTD/fuer/unsere/Gramatik.dtd">
<bla>
</bla>
\end{lstlisting}
\subsection{Format der XSLT-Templates}
\begin{lstlisting}[language=XML,caption=XSLT Templates]
<xsl:template match="bla"> <!-- XPath-Ausdruck -->
<!-- Text und Strukturen, welche im Zieldokument den bla-Knoten aus
dem Quelldokument darstellen und "ersetzen" sollen, z.B.
-->
<html><head>...</head><body>...</body></html>
</xsl:template>
\end{lstlisting}
In \autoref{sec:xslt_detailed} wird \acs{XSLT} genauer beschrieben.
\section{Der XPath-Ausdruck}
Der \acs{XPath}-Ausdruck\footnote{siehe auch \url{https://de.wikipedia.org/wiki/XPath\#Achsen}}
\begin{itemize}
\item besteht aus einem oder mehreren Lokalisierungssschritte, optional gefolgt von Prädikaten
\item mehrere Lokalisierungssschritte werden durch \enquote{/} getrennt
\item ein Lokalisierungsschritt besteht aus Achse und Knotentest:\newline
\code{axis::node-test[predicate]/\ldots}
\end{itemize}
\newpage
\subsection{Achsen}
Achsen geben das \enquote{Verwandtschaftsverhältnis} der aufzusammelnden (gesuchten) zum aktuellen Knoten an.
\begin{tabular}{rp{10.8cm}}
\code{child}: & direkter Kindsknoten \\
\code{parent}: & der Elternknoten \\
\code{descendent}: & alle Nachfahrenknoten \\
\code{ancestor}: & alle Vorfahrenknoten \\
\code{descendent-or-self}: & Vereinigungsmenge von descendent und self \\
\code{ancestor-or-self}: & Vereinigungsmenge von ancestor und self \\
\code{preceding}: & Vorgängerknoten (ohne ancestor!) \\
\code{following}: & Nachfolgeknoten (ohne descendent!) \\
\code{preceding-sibling}: & ältere Geschwisterknoten (preceding mit demselben parent)\\
\code{following-sibling}: & jüngere Geschwisterknoten (following mit demselben parent)\\
\code{attribute}: & am aktuellen Knoten hängender Attributknoten (alle anderen Achsenausdrücke sammeln nur Element- und keine Attributknoten)
\end{tabular}
\subsubsection{Verkürzte Schreibweise}
Eine Verkürzte Schreibweise der Lokalisierungsschritte für Achsen\footnote{siehe auch \url{https://de.wikipedia.org/wiki/XPath\#Achsen}}
\begin{center}
\begin{tabular}{rcl}
\code{bla} & $\hat{=}$ & \code{child::bla} \\
\code{../bla} & $\hat{=}$ & \code{parent::bla} \\
\code{./} & $\hat{=}$ & \code{self} \\
\code{@fasel} & $\hat{=}$ & \code{attribute::fasel} \\
\end{tabular}
\end{center}
\subsection{Knotentests}
Knotentests schränken die Elementauswahl einer Achse ein:
\begin{tabular}{rp{9.5cm}}
\code{tagname} & nur die Knoten mit dem entsprechenden \code{tagname} (bzw. bei \code{attribute} der \code{attrname}) \\
\code{*} & Alle Knoten (Wildcard) \\
\code{text()} & Alle Textknoten \\
\code{comment()} & Für Kommentarknoten \\
\code{processing-instruction()} & für Knoten mit \enquote{processing instructions}\\
\end{tabular}
\subsection{Prädikate}
Durch Angabe von Prädikaten kann das Ergebnis weiter eingeschränkt werden. Prädikate werden in eckige Klammern eingeschlossen und können in beliebiger Zahl hintereinander geschrieben werden, wobei die Reihenfolge wesentlich ist. Prädikate können \acs{XPath}-Ausdrücke enthalten, außerdem kann eine Vielzahl von Funktionen und Operatoren verwendet werden.\footnote{Quelle: \url{https://de.wikipedia.org/wiki/XPath}}
\begin{center}
\xml{axis::node-test[predicate][/...]}
\end{center}
Es handelt sich um eine Bedingung an die Knoten, welche erfüllt (\enquote{wahr}) sein muss.
\subsubsection{Bedingung}
\begin{tabular}{rp{12.4cm}}
\acs{XPath}-Ausdruck & nicht-leere Knotenmenge ergibt \enquote{wahr} \\
Zahl & (natürliche Zahl) ergibt den einen Knoten mit der entsprechenden Nummer aus der Knotenmenge beginnend mit 1. \\
\enquote{Vergleich} & zweier \acs{XPath}-Ausdrücke auf Gleichheit (\html{=}), kleiner (\html{\&lt;}), größer (\html{\&gt;}), kleinergleich (\html{\&lt;=}), größergleich (\html{\&gt;=}) \\
Verknüpfen & mit logischen Operatoren \code{and}, \code{or}, \code{not}. \\
Zahlenoperationen & +, -, * \\
\end{tabular}
\textsf{\textbf{Funktionen}}
\begin{tabular}{lcl}
\xml{number(Knotenmenge)} & $\Rightarrow$ & nummerischer Wert des \enquote{Werts} einer Knotenmenge \\
\xml{count(Knotenmenge)} & $\Rightarrow$ & Anzahl Knoten in der Knotenmenge \\
\xml{substring(...)} & $\Rightarrow$ & Teilzeichenkette \\
...
\end{tabular}
\section{XSLT - Aufbau}\label{sec:xslt_detailed}
\begin{lstlisting}[language=XML,caption=XSL Template]
<xsl:template match="XPath-Ausdruck">
<!-- Inhalt, welcher vom Template ausgegeben wird -->
</xsl:template>
\end{lstlisting}
Mögliche Inhalte:
\begin{itemize}
\item Tags der Zielsprache \newline
\html{<html><head><title>...</title></head><body>...</body></html>}
\item Text \enquote{bla fasel blubber}. Whitespace wird auf ein Trennzeichen (\enquote{space}) reduziert.
\item Text \xml{<xsl:text> leer zeichen</xsl:text>} $\Rightarrow$ Whitespace bleiben erhalten!
\item \enquote{Werte} aus dem Quelldokument: \xml{<xsl:value-of select="Pfadausdruck" />}
\item \enquote{Wert} einer Knotenmenge
\begin{itemize}[noitemsep]
\item Konkatenation der Werte aller Knoten in der Knotenmenge
\end{itemize}
\item \enquote{Wert} eines Knotens
\begin{itemize}[noitemsep]
\item bei Textknoten: der Text
\item bei Attributknoten: der Text des Wertes des Attributknotens
\item bei Elementknoten: rekursive Ermittlung über alle Kindknoten, welche Element- oder Textknoten (\textit{nicht} Attributknoten) sind (Tiefensuche, keine Breitensuche entsprechend der Notation im \acs{XML}-Dokument).\newline
\begin{tabular}{lcl}
\html{<a>bla fasel blubba</a>} & $\Rightarrow$ & Ein Textknoten an \html{<a>}\\
\html{<a>bla<i>fasel</i>blubba</a>} & $\Rightarrow$ & zwei Textknoten an \html{<a>}
\end{tabular}
\end{itemize}
\end{itemize}
\subsubsection{Attribute}
\html{<p style="color:red;">Dieser Text ist rot</p>} $\Rightarrow$ fester Attributwert
\xml{<xsl:attribute name="Attributname">} $\Rightarrow$ erzeugt einen Attributknoten am soeben neu geöffneten (noch nicht geschlossenen und noch nicht mit Texten oder Elementknoten als Kinder versehen) Elementknoten.
\begin{flushleft}
Wert des Attributs als \acs{XPath}-Ausdruck: \newline
\xml{<xsl:attribute name="style" select="pfad/im/Quelldokument"/>}
Wert des Attributs als \enquote{errechneter} Wert im Quelltext:\newline
\xml{<xsl:attribute name="style">color:<xsl:value-of select="..." /></xsl:attribute>}
\end{flushleft}
\subsection{Aufruf der Templates}
\begin{itemize}
\item muss explizit erfolgen
\item das \code{match}-Attribut sorgt \textit{nicht} für den Aufruf/die Ausführung des Transformators
\item der \acs{XSLT} ruft ein Template für den Wurzeltag auf doch
\item mittels \xml{<xsl:apply-templates ...>} können Templates rekursiv aufgerufen werden
\begin{itemize}[noitemsep]
\item \xml{<xsl:apply-templates />} Template Aufruf für alle Kindelemente
\item \xml{<xsl:apply-templates select="Pfadausdruck />} Template-Aufruf für alle Knoten der adressierten Knotenmenge (nicht nur Kinder- und Elementknoten)
\end{itemize}
\item \enquote{schnelle} Alternative zur Rekursion: iterativer Durchgang durch eine Knotenmenge \medskip
\begin{lstlisting}[language=XML,caption=XSLT -- for-each]
<xsl:for-each select="Pfadausdruck">
<!-- Ausgabe für jeden Knoten der Knotenmenge -->
</xsl:for-each>\end{lstlisting}
\item Sortierung der Knoten bei \xml{<xsl:apply-templates/>} und \xml{<xsl:for-each ...>} vor Durchgang durch die Knotenmenge:\newline
\xml{<xsl:sort select="XPath-Ausdruck als Sortierkriterium" />}\newline
als erste Kinder des \xml{<xsl:apply-templates ...>} bzw. \xml{<xsl:for-each ..>}\newline
$\Rightarrow$ mehrere Sortierkriterien sind möglich (durch mehrere \xml{<xsl:sort>} nacheinander)
\item weitere Möglichkeiten zu Templates: \medskip
\begin{lstlisting}[language=XML,caption=XSLT -- Mode]
<xsl:template match="..." mode="Bezeichner">
<!-- dieses Template wir nur bei Aufruf mit gleichem mode-Attributwert ausgefüht -->
</xsl:template>\end{lstlisting}
Aufruf per: \xml{<xsl:apply-templates select="..." mode="Bezeichner" />}
\item Falls kein passendes selbstgeschriebenes Template existiert, existiert ein Default-Template (\textit{ohne} mode-Attribut), welches alle Textknoten und für Elementknoten Templates rekursiv aufruft.
\end{itemize}
Zweite Art von Templates: \enquote{named templates}/Templates mit Namen\medskip
\begin{lstlisting}[language=XML,caption=XSLT -- Benannte Templates]
<xsl:template name="Bezeichner">
<!-- Ausgabe -->
<!-- Pfadausdrücke werden relativ zum aktuellen Knoten, welcher sich beim
Template-Aufruf nicht verändert hat, berechnet
-->
</xsl:template>
\end{lstlisting}
Aufruf per: \xml{<xsl:call-template name="Bezeichner" />}
\newpage
\subsection{Parameter und Variablen}
Parameter können im Template definiert werden: \newline
\xml{<xsl:param name="Bezeichner">Default-Wert</xsl:param>}
Aufruf mittels: \xml{<xsl:with-param name="Bezeichner">Wert</xsl:with-param>} innerhalb von \xml{<xsl:apply-templates>} oder \xml{<xsl:call-template>}. \newline
Nutzung per \code{\$Bezeichner} innerhalb von \acs{XPath}-Ausdrücken.
\enquote{Variablen} können in einem Block (und auch direkt innerhalb von \xml{<xsl:stylesheet>} als \enquote{globale Variable}) definiert werden mittels:\newline
\xml{<xsl:variable name="Bezeichner">Wert</xsl:variable>} und Verwendung mittels \code{\$Bezeichner}.
\textit{Aber}: Der Wert einer \enquote{Variablen} ist nicht veränderbar, sondern fest. Es handelt sich also eher um Konstanten.
\xml{<xsl:param>} kann auch direkt im \xml{<xsl:stylesheet>} genutzt werden, um Parameter beim Aufruf des Stylesheets zu übergeben!
\subsection{Bedingtes Ausführen}
\begin{lstlisting}[language=XML,caption=XSLT -- Bedingtes Ausführen]
<xsl:if test="Bedingung">
<!-- Ausgabe/Ausführung, falls Bedingung erfüllt ist -->
<xsl:if>
<xsl:choose>
<xsl:when test="Bedingug 1">...</xsl:when>
<xsl:when test="Bedingug 2">...</xsl:when>
<xsl:otherwise>
<!--Default-Zweig, falls keine Bedingung erfüllt wurde -->
</xsl:otherwise>
</xsl:choose>
\end{lstlisting}
Bei der \acs{XSLT} If-Abfrage gibt es kein \code{else}!