我刚接触XSLT,目前正在寻找解决问题的方法:
我想输出一个节点<artnr><xsl:value-of select="sku" /></artnr>
n次,其中“ n”是另一个属性<xsl:value-of select="qty" />
的值。
例如:
“ sku”的值为12345,“ qty”的值为3。
输出应如下所示:
<products>
<artnr>12345</artnr>
<artnr>12345</artnr>
<artnr>12345</artnr>
</products>
到目前为止,我已经准备了以下模板,但效率不高:
<products>
<xsl:for-each select="items/item">
<xsl:if test="qty = 1">
<artnr><xsl:value-of select="sku" /></artnr>
</xsl:if>
<xsl:if test="qty = 2">
<artnr><xsl:value-of select="sku" /></artnr>
<artnr><xsl:value-of select="sku" /></artnr>
</xsl:if>
<!-- etc. -->
</xsl:for-each>
</products>
要涵盖所有现实情况,这种方法绝对是不可接受的。在类似情况下,已经在此问题上进行了几次讨论,但是我无法使其在我自己的示例中起作用。
提前谢谢!
答案 0 :(得分:1)
在 XSLT 2.0 中,xsl:for-each
循环的变体中有
select="1 to <final_value>"
。
在您的情况下,此 final_value 由qty
元素给出。
但是还需要采取其他措施。因为在xsl:for-each
上下文中
item更改为循环的当前元素(在本例中为数字),
您必须:
item
元素)保存在变量中
(我叫itm
),sku
的 XPath 表达式的起点
子元素。因此整个脚本如下所示:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<products>
<xsl:for-each select="items/item">
<xsl:copy>
<xsl:variable name="itm" select="."/>
<xsl:for-each select="1 to qty">
<artnr><xsl:value-of select="$itm/sku" /></artnr>
</xsl:for-each>
</xsl:copy>
</xsl:for-each>
</products>
</xsl:template>
</xsl:transform>
有关使用源XML的工作示例,请参见:http://xsltransform.net/pNEhB36
如果您被迫使用 XSLT 1.0 ,则必须使用递归模板, 一次又一次地调用自己,直到定义的深度( 参数)。
我写了以上示例,假设qty
和sku
都是
子元素。但是现在我意识到你实际上写了
至少qty
是属性。
因此item
元素可以例如:
<item qty="2">
<sku>23456</sku>
</item>
然后应该写qty
而不是“普通” @qty
。
答案 1 :(得分:0)
如果限于1.0,这是递归模板的示例。
感谢示例XML输入@Valdi_Bo:-)
注意:这假设qty
将大于零。如果数量可以为零,则需要在输出artnr
之前添加测试。
XML输入
<items>
<item>
<qty>3</qty>
<sku>12345</sku>
</item>
<item>
<qty>2</qty>
<sku>23456</sku>
</item>
<item>
<qty>1</qty>
<sku>34567</sku>
</item>
</items>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="items">
<products>
<xsl:apply-templates/>
</products>
</xsl:template>
<xsl:template match="item">
<xsl:call-template name="output_sku"/>
</xsl:template>
<xsl:template name="output_sku">
<xsl:param name="qty" select="qty"/>
<xsl:variable name="remaining_qty" select="$qty - 1"/>
<artnr>
<xsl:value-of select="sku"/>
</artnr>
<xsl:if test="$remaining_qty >= 1">
<xsl:call-template name="output_sku">
<xsl:with-param name="qty" select="$remaining_qty"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
输出
<products>
<artnr>12345</artnr>
<artnr>12345</artnr>
<artnr>12345</artnr>
<artnr>23456</artnr>
<artnr>23456</artnr>
<artnr>34567</artnr>
</products>
答案 2 :(得分:-1)
以下是一个(更复杂的) XSLT-1.0 解决方案。
它使用样式表中的专用元素。此元素cnt:items
中的元素数是计数的最大数量。因此,如果有10个元素,则xsl:for-each
最多可以计数10个。这有点难看,但这是获得计数器的一种方法。因此,请注意其限制。我还重新组织了模板,但是您可以将其改回使用其他xsl:for-each
。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:cnt="http://counter.com" exclude-result-prefixes="cnt" version="1.0">
<xsl:output indent="yes"/>
<cnt:items><item /><item /><item /><item /><item /><item /><item /><item /><item /><item /></cnt:items>
<xsl:template match="/root">
<products>
<xsl:apply-templates select="items/item" />
</products>
</xsl:template>
<xsl:template match="item">
<xsl:variable name="curSKU" select="sku" />
<xsl:variable name="cnt" select="qty" />
<xsl:for-each select="document('')/xsl:stylesheet/cnt:items/*[$cnt >= position()]">
<artnr><xsl:value-of select="$curSKU" /></artnr>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>