【问题标题】:How do I nest xsl:for-each from different parts of the xml document?如何从 xml 文档的不同部分嵌套 xsl:for-each?
【发布时间】:2010-10-13 11:57:39
【问题描述】:

我将一个 XSL 放在一起,而不是使用一个 XML 文件作为输入来创建一个 NAnt 构建脚本,该 XML 文件定义了所有需要构建的项目。我们有许多非常相似的项目,它们具有标准布局和已定义的移交区域标准,因此拥有一个定义开发人员想要发生的事情而不是描述需要如何完成的 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>

现在,我可以通过在两条 for-each 行之间定义一个来保存 Mode/@name 值,但这有点混乱,我真正想要做的是翻转下一个,以便构建mode 位于 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>

【问题讨论】:

    标签: xml loops xslt nested xslt-1.0


    【解决方案1】:

    成功的关键是not to use &lt;xsl:for-each&gt; at all

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

    【讨论】:

    • 谢谢,您可能会说我对 xsl 的了解是通过获取一些示例并从那里进行推断而获得的。还有很多东西要学。
    • 我怎样才能在这里达到同样的效果:stackoverflow.com/questions/26530125/… 谢谢
    • @SearchForKnowledge 我看过你的问题。我不知道这与我在这里的回答有什么关系。
    【解决方案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>
    

    【讨论】:

      【解决方案3】:

      您可以使用命名模板:

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

      这将有助于区分事物,但我不确定它是否真的更清楚。

      不幸的是,无论您如何看待它,您都必须做一些工作,因为您要同时尝试并获取两个上下文。

      【讨论】:

        【解决方案4】:

        您可以使用变量来存储项目上下文。还有一个清理属性定义的简写

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

        【讨论】:

          猜你喜欢
          • 2010-12-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多