Рассчитать общую сумму корзины в XSLT 1.0 с рекурсией

Я не могу найти ошибку в моей рекурсии. Я надеялся, что ты поможешь мне. Я пытаюсь рассчитать общую стоимость товаров в корзине, но приведенный ниже код дает гораздо более высокий результат, чем ожидалось.

Вот XML:

<products>
    <entry id="123">
        <price>100</price>
    </entry>
    <entry id="456">
        <price>150</price>
    </entry>
</products>
<storage>
    <item id="123" count="2" />
    <item id="456" count="3" />
</storage>

И XSLT:

<xsl:apply-templates select="products/entry" />

<xsl:template match="products/entry">
    <xsl:param name="running-total" select="0"/>
    <xsl:variable name="price" select="price" />
    <xsl:variable name="quantity" select="storage/item[@id = current()/@id]/@count" />
    <xsl:choose>
        <xsl:when test="following-sibling::entry[1]">
            <xsl:apply-templates select="following-sibling::entry[1]">
                <xsl:with-param name="running-total" select="$price * $quantity + $running-total"/>
            </xsl:apply-templates>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$price * $quantity + $running-total"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Спасибо! Буду признателен за любые советы о том, что я делаю неправильно.

1 ответ

Решение

Ваша рекурсия занимает один <entry> за один раз вам нужно начинать его с первого, а не со всех. дела

<xsl:apply-templates select="products/entry[1]" />

Дает правильный вывод:

650

Кроме того, как @zx485 отмечает в комментариях, это

<xsl:variable name="quantity" select="storage/item[@id = current()/@id]/@count" />

работает в контексте <entry>так что так работать не может. Используйте абсолютный путь к лайку /root/storage/item[...] если вы в настоящее время получаете NaN как твой результат.

Сказав это, вы можете немного упростить ваш рекурсивный шаблон:

<xsl:template match="products/entry">
    <xsl:param name="running-total" select="0"/>
    <xsl:variable name="quantity" select="/root/storage/item[@id = current()/@id]/@count" />
    <xsl:apply-templates select="following-sibling::entry[1]">
        <xsl:with-param name="running-total" select="price * $quantity + $running-total"/>
    </xsl:apply-templates>
    <xsl:if test="not(following-sibling::entry)">
        <xsl:value-of select="price * $quantity + $running-total"/>
    </xsl:if>
</xsl:template>

Вы могли бы использовать <xsl:key> для более чистых "количественных" поисков тоже:

<xsl:key name="quantity" match="storage/item/@count" use="../@id" />

<xsl:template match="products/entry">
    <xsl:param name="running-total" select="0"/>
    <xsl:variable name="total" select="price * key('quantity', @id) + $running-total" />
    <xsl:apply-templates select="following-sibling::entry[1]">
        <xsl:with-param name="running-total" select="$total"/>
    </xsl:apply-templates>
    <xsl:if test="not(following-sibling::entry)">
        <xsl:value-of select="$total"/>
    </xsl:if>
</xsl:template>
Другие вопросы по тегам