2009-03-15 16 views
0

Ich setze ein XSL zusammen, als ein NAnt-Build-Skript erstellen wird, das als Eingabe eine XML-Datei verwendet, die alle Elemente definiert, die erstellt werden müssen. Wir haben viele sehr ähnliche Projekte mit Standardlayouts und definierten Standards für Handover-Bereiche. Eine XML-Datei, die definiert, was die Entwickler machen wollen, anstatt zu beschreiben, wie sie durchgeführt werden muss, würde die Akzeptanz des Build-Service erheblich verbessern.Wie neste ich xsl: for-each aus verschiedenen Teilen des XML-Dokuments?

Ich möchte schon früh im Produkt Build XML-Datei die Build-Modi definieren, verwendet werden, dh

<Build> 
    <BuildModes> 
     <Mode name="Debug" /> 
     <Mode name="Release" /> 
    </BuildModes> 

    <ItemsToBuild> 
     <Item name="first item" .... /> 
     <Item name="second item" .... /> 
    </ItemsToBuild> 
</Build> 

Ich möchte eine

<xsl:for-each select="/Build/BuildModes/Mode"> 
    <xsl:for-each select="/Build/ItemsToBuild/Item"> 
     <exec program="devenv"> 
     <xsl:attribute name="line"> 
      use the @name from the Mode and other stuff from Item to build up the command line 
     </xsl:attribute> 
    </xsl:for-each> 
</xsl:for-each> 

nun haben, ich kann es tun, indem Ich habe eine Definition zwischen den beiden für jede Zeile, um den Wert für Mode/@ name zu behalten, aber das ist ein bisschen unordentlich, und was ich eigentlich machen möchte, ist das Umdrehen der Umgebung, so dass der Build-Modus innerhalb der Item-Schleife ist Modus dann der andere. Im Moment würde es alle Debug-Builds und dann alle Release-Builds erstellen. Um das zu tun, müsste ich mehrere erklären lassen, und das wird sehr unordentlich.

So ist es verschachtelt, wenn die Elemente im Quelldokument nicht verschachtelt sind.

EDIT:

ok, wie die akzeptierte Antwort unten zeigt für-jede Verwendung in den meisten Fällen eine schlechte Idee ist, und ich habe dieses Beispiel in den folgenden überarbeitet. Es ist etwas anders, da das Schema, das ich verwende, für den obigen Beitrag vereinfacht wurde, aber Sie bekommen die Idee.

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" encoding="ISO-8859-1" indent="yes"/> 

<xsl:template match="/BuildDefinition"> 
    <xsl:apply-templates select="/BuildDefinition/VS2008SLN/DeploymentProject"/> 
</xsl:template> 

<xsl:template match="/BuildDefinition/VS2008SLN/DeploymentProject"> 
    <xsl:apply-templates select="/BuildDefinition/BuildModes/Mode"> 
     <xsl:with-param name="BuildTarget" select="." /> 
    </xsl:apply-templates> 
</xsl:template> 

<xsl:template match="/BuildDefinition/BuildModes/Mode"> 
    <xsl:param name="BuildTarget" /> 
    <exec program="devenv"> <!-- not the real call, but for example purposes --> 
     <xsl:attribute name="ProjectName" select="$BuildTarget/@ProjectName"/> 
     <xsl:attribute name="SolutionName" select="$BuildTarget/../@SolutionName" /> 
     <xsl:attribute name="ModeName" select="@name"/> 
    </exec> 
</xsl:template> 
</xsl:stylesheet> 

und das ist das Schema, gegen die es läuft

<BuildDefinition Version="1.0"> 

<BuildModes> 
    <Mode name="Debug" /> 
    <Mode name="Release" /> 
</BuildModes> 

<VS2008SLN 
    SolutionName="MySolution" 
    SolutionDirectory="Visual Studio 2008\MySolution"> 
    <DeploymentProject 
     ProjectName="MyDeploymentProject" 
     DeploymentTargetDirectory="EndsUpHere" 
     DeploymentManifestName="AndCalledThisInTheDocumentation" /> 
</VS2008SLN> 

Antwort

7

Der Schlüssel zum Erfolg not to use <xsl:for-each> at all ist.

<xsl:template match="/"> 
    <xsl:apply-templates select="Build/BuildModes/Mode" /> 
</xsl:template> 

<xsl:template match="Build/BuildModes/Mode"> 
    <exec program="devenv"> 
    <xsl:apply-templates select="/Build/ItemsToBuild/Item"> 
     <xsl:with-param name="BuildMode" select="." /> 
    </xsl:apply-templates> 
    </exec> 
</xsl:template> 

<xsl:template match="Build/ItemsToBuild/Item"> 
    <xsl:param name="BuildMode" /> 
    <xsl:attribute name="line"> 
    <!-- use $BuildMode/@name etc. to build up the command line --> 
    </xsl:attribute> 
</xsl:template> 
+0

Vielen Dank, wie Sie wahrscheinlich wissen können, wurde mein Wissen von xsl aus dem Ergreifen einiger Beispiele gewonnen und von dort extrapolieren. Viel mehr zu lernen. –

+0

Wie kann ich das gleiche hier erreichen: http://stackoverflow.com/questions/26530125/how-to-use-xslt-to-display-xml-to-the-browser Danke – SearchForKnowledge

+0

@SearchForKnowledge Ich habe mir deine Frage angeschaut . Ich habe keine Ahnung, wie das mit meiner Antwort hier zusammenhängt. – Tomalak

1

Sie eine benannte Vorlage verwenden:

<xsl:template name="execute"> 
    <xsl:param name="mode" /> 
    <xsl:for-each select="/Build/ItemsToBuild/Item"> 
    <exec program="devenv"> 
    <xsl:attribute name="line"> 
     use $mode and other stuff from Item to build up the command line 
    </xsl:attribute> 
    </exec> 
    </xsl:for-each> 
</xsl:template> 

es dann nennen:

<xsl:for-each select="/Build/BuildModes/Mode"> 
<xsl:call-template name="execute"> 
    <xsl:with-param name="mode" select="@name" /> 
</xsl:call-template> 
</xsl:for-each> 

Dieser Wille Hilfe trennen Dinge, aber ich bin mir nicht sicher, dass es rea ist ly mehr klar.

Leider, egal wie Sie es betrachten, müssen Sie einige Installateure tun, da Sie versuchen und zwei Kontexte gleichzeitig erhalten.

2

Ich denke, die Schlüsseltechnik, die Sie wahrscheinlich vermissen, ist das Speichern des aktuellen Kontextknotens in einer Variablen, bevor Sie etwas tun, das Kontextknoten ändert. Was Sie haben, kann zum Arbeiten gebracht werden, wenn Sie diese Technik verwenden, die das folgende Beispiel verwendet.

Wie viele XSLT-Probleme ist dies einfacher zu lösen, wenn Sie in Transformationen anstelle von Prozeduren denken. Die Frage ist nicht wirklich "Wie verschachtele ich für jede Schleife?", Es ist "Wie transformiere ich Item Elemente in die gewünschten exec Elemente?"

<xsl:template match="/"> 
    <output> 
     <xsl:apply-templates select="/Build/ItemsToBuild/Item"/> 
    </output> 
</xsl:template> 

<xsl:template match="Item"> 
    <xsl:variable name="item" select="."/> 
    <xsl:for-each select="/Build/BuildModes/Mode"> 
     <exec program="devenv"> 
     <xsl:attribute name="itemName" select="$item/@name"/> 
     <xsl:attribute name="modeName" select="@name"/> 
     <!-- and so on --> 
     </exec> 
    </xsl:for-each> 
</xsl:template> 
0

können Sie verwenden eine Variable die Item-Kontext zu speichern. Außerdem gibt es eine Kurzschrift zum Aufräumen der Attributdefinitionen.

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="/"> 
     <someroot> 
      <xsl:for-each select="/Build/ItemsToBuild/Item"> 
       <xsl:variable name="item" select="." /> 
       <xsl:for-each select="/Build/BuildModes/Mode"> 
        <exec program="devenv" 
         item="{$item/@name}" line="{@name}" /> 
       </xsl:for-each> 
      </xsl:for-each> 
     </someroot> 
    </xsl:template> 
</xsl:stylesheet> 

Ergebnis ist

<someroot> 
    <exec program="devenv" item="item1" line="Debug" /> 
    <exec program="devenv" item="item1" line="Release" /> 
    <exec program="devenv" item="item2" line="Debug" /> 
    <exec program="devenv" item="item2" line="Release" /> 
</someroot>