0

ビルドする必要があるすべてのアイテムを定義する XML ファイルを入力として使用して、NAnt ビルド スクリプトを作成する XSL をまとめています。標準的なレイアウトと引き継ぎエリアの定義された標準を備えた非常によく似たプロジェクトがたくさんあります。そのため、どのように実行する必要があるかを説明するのではなく、開発者が何をしたいのかを定義する XML ファイルがあると、ビルド サービスの採用に大きく役立ちます。

製品ビルド XML ファイルの早い段階で、使用するビルド モードを定義したいと考えています。

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

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

私はしたいです

<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>

さて、Mode/@name 値を保持するために 2 つの for-each 行の間に定義を入れることでそれを行うことができますが、それは少し面倒です。実際にやりたいことは、ビルド モードが内側になるようにネクストを反転させることです。 Item ループで、あるモードを構築してから別のモードを構築します。現時点では、すべてのデバッグ ビルドをビルドしてから、すべてのリリース ビルドをビルドします。そのためには、いくつか宣言する必要があり、それは非常に面倒です。

したがって、ソース ドキュメントの要素がネストされていない場合は、ネストされています。

編集:

わかりました、以下の受け入れられた回答が示すように、 for-each を使用することはほとんどの場合悪い考えです。この例を次のように作り直しました。私が使用しているスキーマは上記の投稿用に単純化されているため、少し異なりますが、アイデアはわかります。

<?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>

これは実行対象のスキーマです

<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>
4

4 に答える 4

7

成功の鍵は、まったく使用<xsl:for-each>ないことです。

<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>
于 2009-03-15T20:38:08.543 に答える
2

おそらく欠けている重要なテクニックは、コンテキストノードを変更する何かを行う前に、現在のコンテキストノードを変数に保存することだと思います。以下の例で使用されているその手法を使用すると、得られたものを機能させることができます。

多くの XSLT の問題と同様に、手続きではなく変換を考えれば、これも簡単に解決できます。問題は、「for-each ループをどのように入れ子にするか」ではなく、「Item要素を目的のexec要素に変換するにはどうすればよいか」です。

<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>
于 2009-03-15T19:55:59.020 に答える
1

名前付きテンプレートを使用できます。

<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>

それを呼び出します:

<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>

これは物事を分離するのに役立ちますが、本当にこれ以上明確かどうかはわかりません。

残念ながら、どのように見ても、同時に 2 つのコンテキストを取得しようとしているので、配管工事を行う必要があります。

于 2009-03-15T19:32:15.397 に答える
0

変数を使用して、Item コンテキストを格納できます。また、属性定義をクリーンアップする省略形もあります。

<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>

結果は

<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>
于 2009-03-15T19:57:32.230 に答える