在 if 条件内计数
Count inside an if condition
我有一个 xml 文档,其中包含几个测试定义块。通过 xsl 转换,当它们具有相同的名称时,我想将其中一些测试定义块合并在一起。
合并后,我想为每个合并的测试定义分配一个编号(Order)。
示例输入:
(到处都是0顺序是故意的,因为我现在不知道合并后还有多少测试)
<TestDef>
<Name>Test1</Name>
<Order>0</Order>
<Results>
<Result Name="Result1"/>
<Result Name="Result2"/>
</Results>
</TestDef>
<TestDef>
<Name>Test2</Name>
<Order>0</Order>
<Results>
<Result Name="Result5"/>
<Result Name="Result6"/>
</Results>
</TestDef>
<TestDef>
<Name>Test1</Name>
<Order>0</Order>
<Results>
<Result Name="Result3"/>
<Result Name="Result4"/>
</Results>
</TestDef>
想要的输出:
(现在每个合并测试都分配了一个订单号,从 1 开始无间隙地向上计数)
<TestDef>
<Name>Test1</Name>
<Order>1</Order>
<Results>
<Result Name="Result1"/>
<Result Name="Result2"/>
<Result Name="Result3"/>
<Result Name="Result4"/>
</Results>
</TestDef>
<TestDef>
<Name>Test2</Name>
<Order>2</Order>
<Results>
<Result Name="Result5"/>
<Result Name="Result6"/>
</Results>
</TestDef>
当前输出:
(Test2的Order标签是重点)
<TestDef>
<Name>Test1</Name>
<Order>1</Order>
<Results>
<Result Name="Result1"/>
<Result Name="Result2"/>
<Result Name="Result3"/>
<Result Name="Result4"/>
</Results>
</TestDef>
<TestDef>
<Name>Test2</Name>
<Order>3</Order>
<Results>
<Result Name="Result5"/>
<Result Name="Result6"/>
</Results>
</TestDef>
我当前的 xslt:
<xsl:key name="unique-tests" match="TestDef" use="Name" />
<xsl:strip-space elements="*"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<!-- Merge all tests with the same name together and add all results to
the one new test
This grouping was done, using the Muenchian Method:
http://www.jenitennison.com/xslt/grouping/muenchian.html -->
<xsl:template match="TestDef">
<xsl:if test="generate-id()= generate-id(key('unique-tests', Name))">
<Name>
<xsl:value-of select="Name" />
</Name>
<Order>
<xsl:number />
</Order>
<Results>
<xsl:for-each select="key('unique-tests', Name)">
<xsl:copy-of select="Results/node()"/>
</xsl:for-each>
</Results>
</xsl:if>
</xsl:template>
问题:
分组工作正常,但订单号无法按我希望的方式工作。当我像在我显示的 xslt 中那样使用 <xsl:number/>
时,他将从输入中计算 every 测试,但只输出一些数字。我的示例的输出可能类似于 Test1 with order = 1 和 Test2 with order = 3。
当我在 if 条件之前添加一个额外的输出 <xsl:number/>
时,他会按顺序输出每个数字,即使测试定义本身不会出现在输出中。
现在我看到了其他类似的问题:xsl counter with and condition
在那里他们计算条件,但由于我自己的条件不能表示为 XPath,我不能将它用于 <xsl:number/>
的 count
属性
因此,我希望订单标签从 1 计数到我在 Output 中拥有的任意数量的 TestDef,没有任何间隙。我该如何实现?
恕我直言,最好有选择地应用模板 - 即仅应用于其组中第一个的那些 TestDef
元素 - 然后使用 position()
函数对它们进行编号。
为了演示,我们必须首先有一个有效的 XML 输入和单个根元素,例如:
XML
<root>
<TestDef>
<Name>Test1</Name>
<Order>0</Order>
<Results>
<Result Name="Result1"/>
<Result Name="Result2"/>
</Results>
</TestDef>
<TestDef>
<Name>Test2</Name>
<Order>0</Order>
<Results>
<Result Name="Result5"/>
<Result Name="Result6"/>
</Results>
</TestDef>
<TestDef>
<Name>Test1</Name>
<Order>0</Order>
<Results>
<Result Name="Result3"/>
<Result Name="Result4"/>
</Results>
</TestDef>
</root>
那么你可以这样做:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="unique-tests" match="TestDef" use="Name" />
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates select="TestDef[generate-id() = generate-id(key('unique-tests', Name)[1])]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="TestDef">
<xsl:copy>
<Name><xsl:value-of select="Name" /></Name>
<Order><xsl:value-of select="position()" /></Order>
<Results>
<xsl:for-each select="key('unique-tests', Name)">
<xsl:copy-of select="Results/node()"/>
</xsl:for-each>
</Results>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
或者,您也可以将条件复制到 xsl:number
,方法是:
<xsl:number count="TestDef[generate-id() = generate-id(key('unique-tests', Name)[1])]"/>
我有一个 xml 文档,其中包含几个测试定义块。通过 xsl 转换,当它们具有相同的名称时,我想将其中一些测试定义块合并在一起。 合并后,我想为每个合并的测试定义分配一个编号(Order)。
示例输入: (到处都是0顺序是故意的,因为我现在不知道合并后还有多少测试)
<TestDef>
<Name>Test1</Name>
<Order>0</Order>
<Results>
<Result Name="Result1"/>
<Result Name="Result2"/>
</Results>
</TestDef>
<TestDef>
<Name>Test2</Name>
<Order>0</Order>
<Results>
<Result Name="Result5"/>
<Result Name="Result6"/>
</Results>
</TestDef>
<TestDef>
<Name>Test1</Name>
<Order>0</Order>
<Results>
<Result Name="Result3"/>
<Result Name="Result4"/>
</Results>
</TestDef>
想要的输出: (现在每个合并测试都分配了一个订单号,从 1 开始无间隙地向上计数)
<TestDef>
<Name>Test1</Name>
<Order>1</Order>
<Results>
<Result Name="Result1"/>
<Result Name="Result2"/>
<Result Name="Result3"/>
<Result Name="Result4"/>
</Results>
</TestDef>
<TestDef>
<Name>Test2</Name>
<Order>2</Order>
<Results>
<Result Name="Result5"/>
<Result Name="Result6"/>
</Results>
</TestDef>
当前输出: (Test2的Order标签是重点)
<TestDef>
<Name>Test1</Name>
<Order>1</Order>
<Results>
<Result Name="Result1"/>
<Result Name="Result2"/>
<Result Name="Result3"/>
<Result Name="Result4"/>
</Results>
</TestDef>
<TestDef>
<Name>Test2</Name>
<Order>3</Order>
<Results>
<Result Name="Result5"/>
<Result Name="Result6"/>
</Results>
</TestDef>
我当前的 xslt:
<xsl:key name="unique-tests" match="TestDef" use="Name" />
<xsl:strip-space elements="*"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<!-- Merge all tests with the same name together and add all results to
the one new test
This grouping was done, using the Muenchian Method:
http://www.jenitennison.com/xslt/grouping/muenchian.html -->
<xsl:template match="TestDef">
<xsl:if test="generate-id()= generate-id(key('unique-tests', Name))">
<Name>
<xsl:value-of select="Name" />
</Name>
<Order>
<xsl:number />
</Order>
<Results>
<xsl:for-each select="key('unique-tests', Name)">
<xsl:copy-of select="Results/node()"/>
</xsl:for-each>
</Results>
</xsl:if>
</xsl:template>
问题:
分组工作正常,但订单号无法按我希望的方式工作。当我像在我显示的 xslt 中那样使用 <xsl:number/>
时,他将从输入中计算 every 测试,但只输出一些数字。我的示例的输出可能类似于 Test1 with order = 1 和 Test2 with order = 3。
当我在 if 条件之前添加一个额外的输出 <xsl:number/>
时,他会按顺序输出每个数字,即使测试定义本身不会出现在输出中。
现在我看到了其他类似的问题:xsl counter with and condition
在那里他们计算条件,但由于我自己的条件不能表示为 XPath,我不能将它用于 <xsl:number/>
count
属性
因此,我希望订单标签从 1 计数到我在 Output 中拥有的任意数量的 TestDef,没有任何间隙。我该如何实现?
恕我直言,最好有选择地应用模板 - 即仅应用于其组中第一个的那些 TestDef
元素 - 然后使用 position()
函数对它们进行编号。
为了演示,我们必须首先有一个有效的 XML 输入和单个根元素,例如:
XML
<root>
<TestDef>
<Name>Test1</Name>
<Order>0</Order>
<Results>
<Result Name="Result1"/>
<Result Name="Result2"/>
</Results>
</TestDef>
<TestDef>
<Name>Test2</Name>
<Order>0</Order>
<Results>
<Result Name="Result5"/>
<Result Name="Result6"/>
</Results>
</TestDef>
<TestDef>
<Name>Test1</Name>
<Order>0</Order>
<Results>
<Result Name="Result3"/>
<Result Name="Result4"/>
</Results>
</TestDef>
</root>
那么你可以这样做:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="unique-tests" match="TestDef" use="Name" />
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates select="TestDef[generate-id() = generate-id(key('unique-tests', Name)[1])]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="TestDef">
<xsl:copy>
<Name><xsl:value-of select="Name" /></Name>
<Order><xsl:value-of select="position()" /></Order>
<Results>
<xsl:for-each select="key('unique-tests', Name)">
<xsl:copy-of select="Results/node()"/>
</xsl:for-each>
</Results>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
或者,您也可以将条件复制到 xsl:number
,方法是:
<xsl:number count="TestDef[generate-id() = generate-id(key('unique-tests', Name)[1])]"/>