4.1.5  Modus vs. Tunnel Lösung

Als Entwickler wird man oft mit der Situation konfrontiert, dass es zur Lösung eines bestimmten Problems mehrere Möglichkeiten gibt und man eine davon auswählen muss.
Hier gilt es einen Trade-Off aus teils konkurrierenden Zielen zu finden, wie das folgende Beispiel zeigt:
<konto nr="123">
    <inhaber>alex</inhaber>
    <vorgang>456</vorgang>
    <eintrag art="soll" datum="2019-05-06">20.56</eintrag>
    <eintrag art="soll" datum="2019-02-21">4.73</eintrag>
    <eintrag art="haben" datum="2019-01-14">1.68</eintrag>
    <eintrag art="soll" datum="2019-09-17">6.45</eintrag>
    <eintrag art="haben" datum="2019-01-03">12.38</eintrag>
    [...]
</konto>
Es gibt nun mehrere Möglichkeiten die Bilanz in zwei Dateien soll.xml und haben.xml aufzusplitten.

4.1.5.1  Schleife

<xsl:template match="/">
    <xsl:result-document href="soll.xml">
        <konto nr="{@nr}">
            <inhaber><xsl:value-of select="inhaber"/></inhaber>
            <vorgang><xsl:value-of select="vorgang"/></vorgang>
            <xsl:for-each select="konto/eintrag">
                <xsl:if test="@art='soll'">
                    <xsl:copy-of select="."/>
                </xsl:if>
            </xsl:for-each>
        </konto>
    </xsl:result-document>
    <xsl:result-document href="haben.xml">
        [...]
</xsl:template>
Hier werden die gemeinsamen Felder für das Konto <inhaber> und <vorgang> hartcodiert, was in dem einfachen Beispiel okay wäre. Sollte das XML Gerüst aber umfangreicher sein, dann fällt diese Lösung offensichtlich aus. Abgesehen davon wollen wir ja Pull-Stylesheets vermeiden, vgl. Push vs. Pull Stylesheets.

4.1.5.2  Tunnel Parameter

<xsl:template match="/">
    <xsl:result-document href="soll.xml">
        <xsl:apply-templates>
            <xsl:with-param name="is-soll" select="true()" tunnel="yes"/>
        </xsl:apply-templates>
    </xsl:result-document>
    <xsl:result-document href="haben.xml">
        <xsl:apply-templates>
            <xsl:with-param name="is-soll" select="false()" tunnel="yes"/>
        </xsl:apply-templates>
    </xsl:result-document>
</xsl:template>
    
<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>
    
<xsl:template match="eintrag">
    <xsl:param name="is-soll" tunnel="yes"/>
    <xsl:choose>
        <xsl:when test="$is-soll and @art='soll'">
            <xsl:copy-of select="."/>
        </xsl:when>
        <xsl:when test="not($is-soll) and @art='haben'">
            <xsl:copy-of select="."/>
        </xsl:when>
        <xsl:otherwise/>
    </xsl:choose>
</xsl:template>
Hier werden über eine Default-Kopierregel alle Knoten des XML Gerüsts kopiert, d.h. das Gerüst kann beliebig gross sein, und wir brauchen uns darum nicht zümmern. Insofern ist diese Lösung einen Schritt weit generischer, als die zuvor gezeigte.
Wir sind sogar sehr flexibel was Änderungen angeht, da im Eintrag-Template leicht weitere Logik implementiert werden kann, die über alle Zweige der bedingten Anweisung greift, bspw. mittels einer lokalen Variablen, die einen Berechnungsausdruck enthält.

4.1.5.3  Mode Attribut

(Noch) kürzer geht es dagegen mit dem mode Attribut:
<xsl:template match="/">
    <xsl:result-document href="soll.xml">
        <xsl:apply-templates mode="soll"/>
    </xsl:result-document>
    <xsl:result-document href="haben.xml">
        <xsl:apply-templates mode="haben"/>
    </xsl:result-document>
</xsl:template>
    
<xsl:template match="node()|@*" mode="#all">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*" mode="#current"/>
    </xsl:copy>
</xsl:template>
    
<xsl:template match="eintrag[@art='soll']" mode="haben"/>
<xsl:template match="eintrag[@art='haben']" mode="soll"/>
Der Trick ist hier, dass im jeweils anderen Modus, gerade die ausgewählten Knoten nicht kopiert werden, was schliesslich die Eingabe korrekt in Soll und Haben aufteilt. Wenn wir weitere Logik hinzufügen wollen, müssten wir die Templates ein bisschen umbauen, was nicht weiter tragisch sein sollte.
Der Trade-Off besteht also aus den meist konkurrierenden Zielen Redundanz einzusparen, d.h. den Quelltext so kurz und knapp wie möglich zu gestalten, und einer zukünftigen leichten Erweiterbarkeit.
Previous Page Next Page
Version: 93
Jan 25 2021