0

使用这样的输入 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>

我发现显然匹配、选择或序列构造函数中的任何模式的扫描都必须是静止的。我可以访问当前元素的属性值,但不能访问子元素或当前元素之前的任何内容。

我想知道我正在尝试做的事情是否甚至可以在流模式下使用累加器 - 我很确定我可以使用迭代器参数完成我的目标,但如果我这样做似乎是一个很大的限制我正确理解文档。

4

1 回答 1

0

据我了解,使用流式累加器存储元素内容的唯一方法是匹配文本子节点,例如

<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,这会有点痛苦,我当然建议人们不要明确选择文本节点,除非他们必须处理混合内容,但我发现使用流式传输会迫使您更改 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
于 2018-02-26T09:25:46.717 回答