如何从xml文档的不同部分嵌套xsl:for?
我将把一个XSL放在一起,然后创建一个NAnt构建脚本,使用一个XML文件作为输入,该文件定义了所有需要构建的项。我们有很多非常类似的项目,它们都有标准的布局和为移交区域定义的标准,因此有一个XML文件来定义开发人员希望发生的事情,而不是描述需要如何完成,这将极大地帮助构建服务的使用 我想在产品构建XML文件的早期定义要使用的构建模式,即如何从xml文档的不同部分嵌套xsl:for?,xml,loops,xslt,nested,xslt-1.0,Xml,Loops,Xslt,Nested,Xslt 1.0,我将把一个XSL放在一起,然后创建一个NAnt构建脚本,使用一个XML文件作为输入,该文件定义了所有需要构建的项。我们有很多非常类似的项目,它们都有标准的布局和为移交区域定义的标准,因此有一个XML文件来定义开发人员希望发生的事情,而不是描述需要如何完成,这将极大地帮助构建服务的使用 我想在产品构建XML文件的早期定义要使用的构建模式,即 <Build> <BuildModes> <Mode name="Debug" />
<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和Item中的其他内容来构建命令行
现在,我可以通过在两行之间为每行定义一个值来保存Mode/@name值,但这有点混乱,我实际上想要做的是翻转nexting,使构建模式在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>
您可以使用命名模板:
<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>
使用$mode和Item中的其他内容来构建命令行
那就叫它:
<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>
这将有助于区分事物,但我不确定它是否真的更清晰
不幸的是,无论您如何看待它,您都必须进行一些清理工作,因为您正在尝试同时获取两个上下文。我认为您可能缺少的关键技术是在更改上下文节点之前将当前上下文节点保存在变量中。如果您使用下面的示例所使用的技术,那么您所拥有的可以发挥作用 与许多XSLT问题一样,如果您考虑转换而不是过程,则更容易解决这一问题。问题不是“如何为每个循环嵌套?”,而是“如何将
Item
元素转换为所需的exec
元素?”
您可以使用变量来存储项目上下文。此外,还有一个用于清理属性定义的速记
<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>
成功的关键在于
谢谢您,您可能会告诉我,我对xsl的了解是从抓取一些示例并从中推断出来的。还有很多需要学习。我如何才能在这里实现同样的目标:Thanks@SearchForKnowledge我已经看过你的问题了。我不知道这和我的回答有什么关系。
<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>
<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>