Вот решение с использованием XSLT2, в котором множество узлов являются объектами первого класса. В XSLT1 вам нужно будет использовать расширение узла.
Объяснение ниже:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:variable name="extendedItems" as="xs:integer*">
<xsl:for-each select="//Item">
<xsl:value-of select="./Price * ./Quantity"/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="total">
<xsl:value-of select="sum($extendedItems)"/>
</xsl:variable>
<xsl:template match="//QuantityTotal">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:value-of select="$total"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
подход здесь заключается в использовании «тождественное преобразование», чтобы скопировать документ, при выполнении расчетов и вставить результат в выходной шаблон QuantityTotal. Первый шаблон копирует вход в выходной файл, но переопределяется более конкретным шаблоном для QuantityTotal внизу. Первое объявление переменной создает список расширенных затрат, а второе определение переменной суммирует затраты для получения общей суммы. Затем сумма вставляется в узел NumberTotal.
Ключом к пониманию XSL является то, что он носит декларативный характер. Наиболее распространенная концептуальная ошибка, допущенная почти всеми новичками, заключается в том, что таблица стилей является последовательной программой, обрабатывающей входной XML-документ. На самом деле все наоборот. XSL-движок читает XML-документ. и для каждого нового тега, с которым он сталкивается, он просматривает таблицу стилей для «лучшего» соответствия, выполняя этот шаблон.
EDIT:
Вот версия xslt1.1, которая работает с Saxon 6,5
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ex="http://exslt.org/common"
extension-element-prefixes="ex"
version="1.1">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:variable name="extendedItems">
<xsl:for-each select="//Item">
<extended>
<xsl:value-of select="./Price * ./Quantity"/>
</extended>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="total">
<xsl:value-of select="sum(ex:node-set($extendedItems/extended))"/>
</xsl:variable>
<xsl:template match="//QuantityTotal">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:value-of select="$total"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
+1 хороший вопрос –
Хороший вопрос (+1). См. Мой ответ для решений как в XSLT 1.0 (не требуется никаких расширений), так и XSLT 2.0 –
См. Также http://stackoverflow.com/questions/436998/multiply-2-numbers-and-then-sum-with-xslt и http ://переполнение стека.com/questions/1333558/xslt-to-sum-product-of-two-attributes – harpo