XSLT 1.0:计算每一页的小计

Posted

技术标签:

【中文标题】XSLT 1.0:计算每一页的小计【英文标题】:XSLT 1.0: Calculating Subtotal on each page 【发布时间】:2022-01-11 22:49:21 【问题描述】:

源 XML:

<Root>
    <Data>
        <Value>10</Value>
    </Data>
    <Data>
        <Value>10</Value>
    </Data>
    <Data>
        <Value>15</Value>
    </Data>
    <Data>
        <Value>2</Value>
    </Data>
    <Data>
        <Value>32</Value>
    </Data>
    <Data>
        <Value>5</Value>
    </Data>
    <Data>
        <Value>40</Value>
    </Data>
    <Data>
        <Value>18</Value>
    </Data>
    <Data>
        <Value>50</Value>
    </Data>
    <Data>
        <Value>1</Value>
    </Data>
    <Data>
        <Value>43</Value>
    </Data>
    <Data>
        <Value>5</Value>
    </Data>
    <Data>
        <Value>21</Value>
    </Data>
    <Data>
        <Value>87</Value>
    </Data>
    <Data>
        <Value>8</Value>
    </Data>
....
</Root>

XSL-FO 代码: 我的代码包含一个表格行和一个表格页脚

<fo:table>
    <fo:table-column column-/>
    <fo:table-column column-/>
    <fo:table-footer>
        <fo:table-row>
            <fo:table-cell>
                <fo:block>Subtotal: </fo:block>
            </fo:table-cell>
            <fo:table-cell>
                <fo:block>
                    <fo:retrieve-table-marker retrieve-class-name="Subtotal" retrieve-position-within-table="last-starting"/>
                </fo:block>
            </fo:table-cell>
        </fo:table-row>
    </fo:table-footer>
    <fo:table-body>
    <xsl:for-each select="/Root/Data">      
     <fo:table-row>
            <fo:table-cell>
                <fo:block>Value:</fo:block>
            </fo:table-cell>
            <fo:table-cell>
                <fo:block> 
                    <xsl:value-of select="Value"/>
                    <fo:marker marker-class-name="Subtotal">
                        <xsl:variable name="position" select="position()"/>
                        <xsl:value-of xpath="sum(../Data[position() &lt;= $position]/Value)"/>
                    </fo:marker>
                </fo:block>
            </fo:table-cell>
        </fo:table-row>
      </xsl:for-each>
    </fo:table-body>
</fo:table>

我正在从上表生成 PDF 输出。在 PDF 中,表格每页最多可以有 15 个表格行。每一页都需要计算小计,只对当前页显示的值求和。

我上面的表格(我发现的唯一解决方案是使用表格标记)计算 Page1 的正确小计,但对于 Page2 等失败。它将所有先前页面的小计附加到当前页面。

例如:如果第1页显示的Value元素小计为10,第2页显示的Values小计为20,我的表格将显示在第1页,小计为10,但在第2页,小计将30,而不是 20。谁能帮忙解决这个问题?

提前致谢

【问题讨论】:

每页的行数/数据元素数是否已知(例如 15),以便您可以处理例如for-each select="Root/Data[position() mod 15 = 1]" and then form e.g. ` 并求和,例如sum($data-of-page/Value)? 是的,每页的行数是已知的(不超过 15 页)。非常感谢,这可以计算总和,但现在我正在努力在表格中显示所有 15 个值。通过在 Root/Data[position() mod 15 = 1] 之后重复,只显示第一个元素和总和。 您还可以使用 fo:marker 重写包含小计的标记,然后将该标记检索到页脚区域。页脚区域可能包含包含此小计的“假”表行。见***.com/questions/17195230/… 【参考方案1】:

在 XSLT 1 中使用“位置分组”

<xsl:for-each select="Root/Data[position() mod 15 = 1]">
  <xsl:variable name="data-of-page" select=". | following-sibling::Data[position() &lt; 15]"/>

  <xsl:for-each select="$data-of-page">
     <fo:table-row>
            <fo:table-cell>
                <fo:block>Value:</fo:block>
            </fo:table-cell>
            <fo:table-cell>
                <fo:block> 
                    <xsl:value-of select="Value"/>
                    <xsl:if test="position() = last()">
                      <fo:marker marker-class-name="Subtotal">
                        <xsl:value-of xpath="sum($data-of-page/Value)"/>
                      </fo:marker>
                    </xsl:if>
                </fo:block>
            </fo:table-cell>
        </fo:table-row>
  </xsl:for-each>
</xsl:for-each>

【讨论】:

【参考方案2】:

此版本的唯一优点是如果第一页少于 15 行,它将给出正确的小计;例如,如果表格开始之前有标题或文本。

<xsl:stylesheet
    version="1.0"
    xmlns:axf="http://www.antennahouse.com/names/XSL/Extensions"
    xmlns:fo="http://www.w3.org/1999/XSL/Format"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:strip-space elements="*" />

<xsl:output indent="yes" />

<xsl:variable name="rows-per-page" select="15" />

<xsl:template match="/">
  <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
           xmlns:axf="http://www.antennahouse.com/names/XSL/Extensions"
           xml:lang="en">
    <fo:layout-master-set>
      <fo:simple-page-master master-name="spm" size="A7">
        <fo:region-body margin="20mm" margin-top="15mm" />
      </fo:simple-page-master>
    </fo:layout-master-set>
    <fo:page-sequence master-reference="spm">
      <fo:flow flow-name="xsl-region-body">
        <xsl:apply-templates />
      </fo:flow>
    </fo:page-sequence>
  </fo:root>
</xsl:template>

<xsl:template match="Root">
  <fo:block />
  <fo:table space-before="3lh">
    <fo:table-column column-/>
    <fo:table-column column-/>
    <fo:table-footer>
      <fo:table-row>
        <fo:table-cell>
          <fo:block>Subtotal: </fo:block>
        </fo:table-cell>
        <fo:table-cell>
      <fo:block-container>
            <fo:retrieve-table-marker retrieve-class-name="Remainder" retrieve-position-within-table="first-starting"/>
            <fo:retrieve-table-marker retrieve-class-name="Subtotal" retrieve-position-within-table="last-starting"/>
      </fo:block-container>
        </fo:table-cell>
      </fo:table-row>
    </fo:table-footer>
    <fo:table-body>
      <xsl:apply-templates />
    </fo:table-body>
  </fo:table>
</xsl:template>

<xsl:template match="Data">
  <fo:table-row>
    <fo:table-cell>
      <fo:block>Value:</fo:block>
    </fo:table-cell>
    <fo:table-cell>
      <fo:block>
        <fo:marker marker-class-name="Subtotal">
          <xsl:if test="position() != last()">
          <fo:block-container  background-color="white">
            <fo:block>
              <xsl:value-of
                  select="sum(preceding-sibling::Data[position() &lt; $rows-per-page]) + Value"/>
            </fo:block>
          </fo:block-container>
          </xsl:if>
        </fo:marker>
        <fo:marker marker-class-name="Remainder">
          <fo:block-container  z-index="-1" absolute-position="absolute">
            <fo:block>
              <xsl:value-of
                  select="sum(following-sibling::Data) + Value"/>
            </fo:block>
          </fo:block-container>
        </fo:marker>
        <xsl:value-of select="Value"/>
      </fo:block>
    </fo:table-cell>
  </fo:table-row>
</xsl:template>

</xsl:stylesheet>

【讨论】:

以上是关于XSLT 1.0:计算每一页的小计的主要内容,如果未能解决你的问题,请参考以下文章

xtable大表每一页的标题?

EXCEL表格如何在每一页最后一行自动求一列的和,要求是自动的,不管是多少行只要够一页它就求和

如何将(静态)内容放在 Libreoffice Writer 每一页的右栏中?

在 s-s-rS 矩阵报告中,我需要再显示一列作为最后一列,并且只需要在最后一页显示,而不是作为每一页的最后一列

将第一页的所有 cookie 保存在硬盘上的文本文件中

xsl-fo 删除第一页的页码