XSLT 3 中的条件流式累加器
Conditional Streaming Accumulator in XSLT 3
输入 XML 如下:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Entry>
<Amount>2088</Amount>
<DebitCredit>C</DebitCredit>
</Entry>
<Entry>
<Amount>9074</Amount>
<DebitCredit>D</DebitCredit>
</Entry>
...
</Root>
我想为借方和贷方创建一个带有单独累加器的可流式转换,但是当我尝试为一种或另一种类型创建类似于此的累加器时
<xsl:accumulator name="debitcount" initial-value="0" streamable="yes">
<xsl:accumulator-rule phase="end"
match="Entry[DebitCredit eq 'D']"
select="$value + 1"/>
</xsl:accumulator>
我发现显然匹配中任何模式的扫描,select 或序列构造函数必须是静止的。我可以访问当前元素的属性值,但不能访问子元素或当前元素之前的任何内容。
我想知道在流模式下使用累加器是否可以实现我正在尝试做的事情 - 我很确定我可以使用迭代器参数完成我在这里的目标,但它看起来像如果我正确理解文档的话,会有很大的限制。
据我所知,使用流式累加器存储元素内容的唯一方法是匹配文本子节点,例如
<xsl:accumulator name="current-amount" as="xs:decimal?" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="Entry/Amount/text()" select="xs:decimal(.)"/>
</xsl:accumulator>
那么您应该能够按照类似的规则将这些值相加,例如
<xsl:accumulator name="credit" as="xs:decimal" initial-value="0" streamable="yes">
<xsl:accumulator-rule match="Entry/DebitCredit/text()" select="if (. = 'C') then $value + accumulator-before('current-amount') else $value"/>
</xsl:accumulator>
<xsl:accumulator name="debit" as="xs:decimal" initial-value="0" streamable="yes">
<xsl:accumulator-rule match="Entry/DebitCredit/text()" select="if (. = 'D') then $value - accumulator-before('current-amount') else $value"/>
</xsl:accumulator>
如果您只想计算 DebitCredit/text()[. = 'C']
个节点的数量,则应该使用相同的方法(即匹配文本子节点)。
如果你习惯了正常的 XSLT/XPath ,这会有点痛苦,我当然建议人们永远不要显式地 select 文本节点,除非他们必须处理混合内容,但我发现使用流媒体迫使你改变你的 XSLT/XPath 编码方法。
这里是一个例子,输入是
<Root>
<Entry>
<Amount>100</Amount>
<DebitCredit>C</DebitCredit>
</Entry>
<Entry>
<Amount>50</Amount>
<DebitCredit>D</DebitCredit>
</Entry>
<Entry>
<Amount>10</Amount>
<DebitCredit>C</DebitCredit>
</Entry>
<Entry>
<Amount>20</Amount>
<DebitCredit>D</DebitCredit>
</Entry>
</Root>
带有样式表的 Saxon 9.8.0.8 EE
<?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:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:output method="text"/>
<xsl:mode on-no-match="shallow-skip" streamable="yes" use-accumulators="#all"/>
<xsl:accumulator name="current-amount" as="xs:decimal?" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="Entry/Amount/text()" select="xs:decimal(.)"/>
</xsl:accumulator>
<xsl:accumulator name="credit" as="xs:decimal" initial-value="0" streamable="yes">
<xsl:accumulator-rule match="Entry/DebitCredit/text()" select="if (. = 'C') then $value + accumulator-before('current-amount') else $value"/>
</xsl:accumulator>
<xsl:accumulator name="debit" as="xs:decimal" initial-value="0" streamable="yes">
<xsl:accumulator-rule match="Entry/DebitCredit/text()" select="if (. = 'D') then $value - accumulator-before('current-amount') else $value"/>
</xsl:accumulator>
<xsl:accumulator name="debitcount" initial-value="0" streamable="yes">
<xsl:accumulator-rule
match="Entry/DebitCredit/text()[. = 'D']"
select="$value + 1"/>
</xsl:accumulator>
<xsl:template match="/*" expand-text="yes">
<xsl:apply-templates/>
Debit count {accumulator-after('debitcount')}
Sum of credits {accumulator-after('credit')},
Sum of debits {accumulator-after('debit')}
</xsl:template>
</xsl:stylesheet>
产出
Debit count 2
Sum of credits 110,
Sum of debits -70
输入 XML 如下:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Entry>
<Amount>2088</Amount>
<DebitCredit>C</DebitCredit>
</Entry>
<Entry>
<Amount>9074</Amount>
<DebitCredit>D</DebitCredit>
</Entry>
...
</Root>
我想为借方和贷方创建一个带有单独累加器的可流式转换,但是当我尝试为一种或另一种类型创建类似于此的累加器时
<xsl:accumulator name="debitcount" initial-value="0" streamable="yes">
<xsl:accumulator-rule phase="end"
match="Entry[DebitCredit eq 'D']"
select="$value + 1"/>
</xsl:accumulator>
我发现显然匹配中任何模式的扫描,select 或序列构造函数必须是静止的。我可以访问当前元素的属性值,但不能访问子元素或当前元素之前的任何内容。
我想知道在流模式下使用累加器是否可以实现我正在尝试做的事情 - 我很确定我可以使用迭代器参数完成我在这里的目标,但它看起来像如果我正确理解文档的话,会有很大的限制。
据我所知,使用流式累加器存储元素内容的唯一方法是匹配文本子节点,例如
<xsl:accumulator name="current-amount" as="xs:decimal?" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="Entry/Amount/text()" select="xs:decimal(.)"/>
</xsl:accumulator>
那么您应该能够按照类似的规则将这些值相加,例如
<xsl:accumulator name="credit" as="xs:decimal" initial-value="0" streamable="yes">
<xsl:accumulator-rule match="Entry/DebitCredit/text()" select="if (. = 'C') then $value + accumulator-before('current-amount') else $value"/>
</xsl:accumulator>
<xsl:accumulator name="debit" as="xs:decimal" initial-value="0" streamable="yes">
<xsl:accumulator-rule match="Entry/DebitCredit/text()" select="if (. = 'D') then $value - accumulator-before('current-amount') else $value"/>
</xsl:accumulator>
如果您只想计算 DebitCredit/text()[. = 'C']
个节点的数量,则应该使用相同的方法(即匹配文本子节点)。
如果你习惯了正常的 XSLT/XPath ,这会有点痛苦,我当然建议人们永远不要显式地 select 文本节点,除非他们必须处理混合内容,但我发现使用流媒体迫使你改变你的 XSLT/XPath 编码方法。
这里是一个例子,输入是
<Root>
<Entry>
<Amount>100</Amount>
<DebitCredit>C</DebitCredit>
</Entry>
<Entry>
<Amount>50</Amount>
<DebitCredit>D</DebitCredit>
</Entry>
<Entry>
<Amount>10</Amount>
<DebitCredit>C</DebitCredit>
</Entry>
<Entry>
<Amount>20</Amount>
<DebitCredit>D</DebitCredit>
</Entry>
</Root>
带有样式表的 Saxon 9.8.0.8 EE
<?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:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:output method="text"/>
<xsl:mode on-no-match="shallow-skip" streamable="yes" use-accumulators="#all"/>
<xsl:accumulator name="current-amount" as="xs:decimal?" initial-value="()" streamable="yes">
<xsl:accumulator-rule match="Entry/Amount/text()" select="xs:decimal(.)"/>
</xsl:accumulator>
<xsl:accumulator name="credit" as="xs:decimal" initial-value="0" streamable="yes">
<xsl:accumulator-rule match="Entry/DebitCredit/text()" select="if (. = 'C') then $value + accumulator-before('current-amount') else $value"/>
</xsl:accumulator>
<xsl:accumulator name="debit" as="xs:decimal" initial-value="0" streamable="yes">
<xsl:accumulator-rule match="Entry/DebitCredit/text()" select="if (. = 'D') then $value - accumulator-before('current-amount') else $value"/>
</xsl:accumulator>
<xsl:accumulator name="debitcount" initial-value="0" streamable="yes">
<xsl:accumulator-rule
match="Entry/DebitCredit/text()[. = 'D']"
select="$value + 1"/>
</xsl:accumulator>
<xsl:template match="/*" expand-text="yes">
<xsl:apply-templates/>
Debit count {accumulator-after('debitcount')}
Sum of credits {accumulator-after('credit')},
Sum of debits {accumulator-after('debit')}
</xsl:template>
</xsl:stylesheet>
产出
Debit count 2
Sum of credits 110,
Sum of debits -70