XSLT: повторить вывод значения n раз, в то время как «n» задано значение другого атрибута - PullRequest
0 голосов
/ 17 февраля 2019

Я довольно новичок в 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 голосов
/ 17 февраля 2019

Одно (более сложное) 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>
0 голосов
/ 18 февраля 2019

Вот пример рекурсивного шаблона, если вы ограничены 1.0.

Спасибо за пример XML-ввода @Valdi_Bo: -)

Примечание. Предполагается, что qty будетбыть больше нуля.Если кол-во может быть нулевым, вам нужно добавить тест перед выводом artnr.

XML Input

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

Fiddle: http://xsltfiddle.liberty -development.net / bnnZVQ / 1

0 голосов
/ 17 февраля 2019

В XSLT 2.0 , среди вариантов цикла xsl:for-each есть select="1 to <final_value>".

В вашем случае это final_value задается элементом qty.

Но нужно еще одно действие.Поскольку внутри xsl:for-each элемент контекста изменяется на текущий элемент цикла (в данном случае это число), вы должны:

  • сохранить «внешний» контекст (текущий item)элемент) в переменной (я назвал ее itm),
  • использует эту переменную в качестве начальной точки выражения XPath , относящегося к sku дочернему элементу.

Таким образом, весь скрипт может выглядеть следующим образом:

<?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 , вы должны использовать рекурсивный шаблон, вызывая себя снова и снова, до определенной глубины (один из его параметров).

Edit

Я написал приведенный выше примерпри условии, что qty и sku являются дочерними элементами .Но теперь я понял, что вы на самом деле написали, что по крайней мере qty является атрибутом .

Таким образом, элемент item может быть, например:

<item qty="2">
  <sku>23456</sku>
</item>

Тогда вместо«обычный» qty вы должны написать @qty.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...