XSLT:将值的输出重复n次,而“ n”被赋予另一个属性的值

时间:2019-02-17 20:20:27

标签: xml xslt

我刚接触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>

要涵盖所有现实情况,这种方法绝对是不可接受的。在类似情况下,已经在此问题上进行了几次讨论,但是我无法使其在我自己的示例中起作用。

提前谢谢!

3 个答案:

答案 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 ,则必须使用递归模板, 一次又一次地调用自己,直到定义的深度( 参数)。

编辑

我写了以上示例,假设qtysku都是 子元素。但是现在我意识到你实际上写了 至少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>

提琴:http://xsltfiddle.liberty-development.net/bnnZVQ/1

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