2010-11-21 4 views
4

Ich habe eine Anwendung geschrieben, die eine Pipeline von 15 XSL-Stylesheets verwendet, und ich fange an, daran zu arbeiten, die Leistung zu optimieren. Es ist portabel, sodass es sowohl in der Webbrowser-Umgebung als auch auf dem Desktop ausgeführt werden kann. Auf dem Desktop denke ich, dass es sinnvoll sein könnte, die Stylesheets als Pipeline mit mehreren Transformationen zu trennen, da jede einzelne Transformation in einem eigenen Thread ausgeführt werden kann, was bei CPUs mit mehreren Kernen sehr effizient sein kann. Die Browserumgebung ist jedoch nicht nur single-threaded, in den meisten Browsern erfordert die XSL-Verarbeitungs-API, die für JavaScript verfügbar gemacht wird, das Ergebnis jeder einzelnen Transformation zurück in ein DOM-Objekt zu analysieren, was ineffizient erscheint. Ich denke, es wäre daher von Vorteil, alle Stylesheets in einem einzigen Stylesheet zu kombinieren, wenn dies im Kontext der Browserumgebung möglich ist. Ich habe eine Idee, wie dies mit exsl erreicht werden kann: Node-Set (die meisten Browser unterstützen), aber es ist mir nicht klar, ob die Technik, die ich mir vorstelle, verallgemeinerbar ist. Gibt es eine allgemeine Technik zum Transformieren einer Pipeline von XSL-Stylesheets in ein einziges XSL-Stylesheet, so dass die Semantik der vollständigen Pipeline erhalten bleibt? Eine automatisierte Lösung wäre ideal.Gibt es eine Technik, um eine Pipeline von XSL-Transformationen zu einer einzigen Transformation zu kombinieren?

+0

Gute Frage, +1. Sehen Sie meine Antwort für eine ausführliche Erklärung und für zwei Beispiele der vorgeschlagenen Lösung. –

Antwort

2

Es gibt eine Technik, die es ermöglicht, unabhängige Transformationen zusammenzufassen, wobei die Ausgabe der k-ten Transformation die Eingabe der (k + 1) -ten Transformation ist. Hier

ist ein einfaches Beispiel:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:ext="http://exslt.org/common" 
    exclude-result-prefixes="ext xsl"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="node()|@*" name="identity"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="/"> 
    <xsl:variable name="vrtfPass1"> 
    <xsl:apply-templates select="node()"/> 
    </xsl:variable> 

    <xsl:apply-templates mode="pass2" 
    select="ext:node-set($vrtfPass1)/node()"/> 
</xsl:template> 

<xsl:template match="/*"> 
    <xsl:copy> 
     <xsl:copy-of select="@*"/> 
     <one/> 
    <xsl:apply-templates/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="node()|@*" mode="pass2"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*" mode="pass2"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="/*/one" mode="pass2" > 
    <xsl:call-template name="identity"/> 
     <two/> 
</xsl:template> 
</xsl:stylesheet> 

wenn diese Transformation auf das folgende XML-Dokument angewendet wird:

<doc/> 

das gewünschte Ergebnis (der erste Durchgang addds das Element <one/> als ein Kind des obersten Elements, dann fügt der zweite Durchlauf ein weiteres Kind hinzu, , immediately after the element `das wurde in dem ersten Durchgang erzeugt) ist hergestellt:

<doc> 
    <one/> 
    <two/> 
</doc> 

Es gibt eine sehr passende Vorlage/Funktion in FXSL, dies zu tun: das ist die compose-flist Vorlage. Es verwendet als Parameter ein initiales Datenargument und N Funktionen (Templates) und erzeugt die verkettete Zusammensetzung dieser Funktionen/Templates. Hier

ist der Test Beispiel aus der FXSL Bibliothek:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:f="http://fxsl.sf.net/" 
xmlns:myFun1="f:myFun1" 
xmlns:myFun2="f:myFun2" 
xmlns:ext="http://exslt.org/common" 
exclude-result-prefixes="xsl f ext myFun1 myFun2" 
> 
    <xsl:import href="compose.xsl"/> 
    <xsl:import href="compose-flist.xsl"/> 

    <!-- to be applied on any xml source --> 

    <xsl:output method="text"/> 
    <myFun1:myFun1/> 
    <myFun2:myFun2/> 


    <xsl:template match="/"> 

    <xsl:variable name="vFun1" select="document('')/*/myFun1:*[1]"/> 
    <xsl:variable name="vFun2" select="document('')/*/myFun2:*[1]"/> 
    Compose: 
    (*3).(*2) 3 = 
    <xsl:call-template name="compose"> 
     <xsl:with-param name="pFun1" select="$vFun1"/> 
     <xsl:with-param name="pFun2" select="$vFun2"/> 
     <xsl:with-param name="pArg1" select="3"/> 
    </xsl:call-template> 

    <xsl:variable name="vrtfParam"> 
     <xsl:copy-of select="$vFun1"/> 
     <xsl:copy-of select="$vFun2"/> 
     <xsl:copy-of select="$vFun1"/> 
    </xsl:variable> 

    Multi Compose: 
    (*3).(*2).(*3) 2 = 
    <xsl:call-template name="compose-flist"> 
     <xsl:with-param name="pFunList" select="ext:node-set($vrtfParam)/*"/> 
     <xsl:with-param name="pArg1" select="2"/> 
    </xsl:call-template> 
    </xsl:template> 

    <xsl:template match="myFun1:*" mode="f:FXSL"> 
    <xsl:param name="pArg1"/> 

    <xsl:value-of select="3 * $pArg1"/> 
    </xsl:template> 

    <xsl:template match="myFun2:*" mode="f:FXSL"> 
    <xsl:param name="pArg1"/> 

    <xsl:value-of select="2 * $pArg1"/> 
    </xsl:template> 
</xsl:stylesheet> 

wenn diese Transformation auf jedem XML-Dokument angewendet wird (nicht benutzt), der wollte, korrekte Ergebnis wird hergestellt:

Compose: 
(*3).(*2) 3 = 
18 

Multi Compose: 
(*3).(*2).(*3) 2 = 
36 

Beachten Sie: In XSLT 2.0 und höher ist keine xxx:node-set() Erweiterung erforderlich, und alle der Kette Ed-Transformationen können in einer realen Funktion enthalten sein.

+0

Extrem gründlich. Danke für Ihre Antwort! – jbeard4

0

Ein Ansatz ist, Modi zu verwenden http://www.w3.org/TR/xslt#modes aber Sie haben Recht, dass das erfordert jeder Schritt in eine Variable umzuwandeln und eine Knotenmenge Erweiterungsfunktion zu nutzen, um der Lage sein, den nächsten Schritt zu den variablen Inhalte anzuwenden.

Verwandte Themen