XSL Transoformation - String ohne Duplikate aufbauen

~Lunes~

Commodore
Registriert
Feb. 2006
Beiträge
4.162
Hallo zusammen,

ich sitze momentan an einem Problem und komme einfach nicht weiter, da mir XSL recht neu ist und ich daher noch nicht den Überblick habe, welche Möglichkeiten mir zur Lösung meines Problems zur Verfügung stehen.

Es geht um Folgendes:
- Ich habe ein XML Dokument das transformiert werden soll
- Im ursprünglichen XML kommt in mehreren Elementen eine Belegnummer <bnummer> vor
- Ich muss mir aus diesen Feldern die Belegnummern rausholen und daraus einen String aufbauen, d.h. die einzelnen Belegnummern aneinanderreihen und in ein einziges <comment> Feld im Ausgabe XML schreiben


Das eigentliche Problem dabei ist nun, dass einzelne <bnummer> Belegnummern doppelt vorkommen können. Diese muss ich irgendwie herausfiltern, ohne aber die ursprüngliche Reihenfolge zu verändern. Jetzt meine Frage, wie mache ich dies am geschicktesten?

Die ursprünglichen <bnummer> Felder müssen bestehen bleiben, d.h. die Filterung darf erst bei der String Erstellung zur Befüllung des <comment> Tags erfolgen.

In einer "richtigen" Programmiersprache hätt ich mir einfach den String nach und nach in einer Schleife aufgebaut und jeweils geschaut ob die Nummer schon im String vorhanden ist und wenn nicht einfach hinten angehängt. Durch die Restriktionen gerade was Variablen angeht bin ich hier in XSL aber etwas eingeschränkt :-/
Daher meine Frage, kann man eine ähnliche Vorgehensweise auch in XSL umsetzen und wenn ja wie?

Ich bin für jede Hilfe, jeden Hinweis oder kleinen Anschubser dankbar :)
Noch eine kleine Ergänzung, die Lösung muss XSL 1.0 konform sein.
 
Zuletzt bearbeitet:
Spontan würde mir ein rekusiver Templateaufruf einfallen, der dir den String aufbaut.

Du machst ein Template, dass die bnummer-Elemente als Sequenz, eine Laufvariable (beim ersten Aufruf = 1) und deinen String übergeben bekommt.
Auf die Sequenz kannst du dann über die Laufvariable wie ein Array zugreifen.
Die Prüfung, ob die Nummer im String ist, kannst du somit durchführen.

Solange die Laufvariable nicht der Anzahl der Elemente in der Sequenz entspricht, rufst du dieses Template rekursiv wieder auf, ansonsten gibst du den String mit value-of zurück.
Beim rekursiven Aufruf erhöhst du die Laufvariable um 1, damit du beim nächsten Aufruf, das nächste Element aus der Sequenz aufrufen kannst.

Damit kannst du das Problem mit dem Scope der Variable umgehen.

Hab mal alten Produktivcode von uns verallgemeinert. Musst mal schauen, ob das für dich so passt.

Code:
    <xsl:template match="/">
        <xsl:variable name="endString">            
            <xsl:call-template name="recursiveTemplate">
                <xsl:with-param name="anzahl" select="1" />
                <xsl:with-param name="sequence" select="BNummer-PFAD" />
                <xsl:with-param name="result" select="''" />
            </xsl:call-template> 
        </xsl:variable>
    </xsl:template>
    
    <xsl:template name="recursiveTemplate">
        <xsl:param name="anzahl" />
        <xsl:param name="sequence" />
        <xsl:param name="result" />
        <xsl:variable name="actPos" select="$sequence[$anzahl]" />
        
        <xsl:choose>
            <xsl:when test="contains($result, $actPos)">
                <xsl:call-template name="recursiveTemplate">
                    <xsl:with-param name="anzahl" select="$anzahl + 1" />
                    <xsl:with-param name="sequence" select="$sequence"/>
                    <xsl:with-param name="result" select="$result"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:choose>
                    <xsl:when test="$anzahl = count(//BNummer-PFAD) +1">
                         <xsl:value-of select="$result" />
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:call-template name="recursiveTemplate">
                            <xsl:with-param name="anzahl" select="$anzahl + 1" />
                            <xsl:with-param name="sequence" select="$sequence"/>
                            <xsl:with-param name="result" select="$result + ',' + $actPos" />
                        </xsl:call-template>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:otherwise> 
        </xsl:choose>               
    </xsl:template>
 
Zuletzt bearbeitet:
Vielen Dank für deine Hilfe und das Beispiel, werd's mir die Tage mal näher anschauen versuchen es auf meinen Fall anzuwenden.

Bin aber auch noch in Klärung ob ich nicht einfach XSLT 2 verwenden kann. Da gibt es die kleine aber feine distinct Funktion mit der ich mir einiges sparen könnte.
 
Wenn es der XSLT-Prozessor unterstützt, wäre das natürlich das Beste ;)
XSLT 1.0 ist für solche Sachen extrem umständlich. Eigentlich sollte man solche Sachen gar nicht mit XSLT machen..

Im Beispiel war noch ein Fehler, die Rückgabe war nicht vorhanden. Hab das falsche Template als Grundlage genommen.
 
Zurück
Oben