基于匹配值求和 XSLT-1.0
Summing based on matching values XSLT-1.0
我目前正在尝试使用 XSLT 1.0 中的分组。我有 XML 与此类似:
<table>
<row>
<PRODUCER type="VARCHAR" value="PRODUCER 1"/>
<PUBLICATION_CODE_-_NAME type="VARCHAR" value="PUBLICATION A"/>
<DOMESTIC type="DECIMAL" value="20"/>
<FOREIGN type="DECIMAL" value="4"/>
</row>
<row>
<PRODUCER type="VARCHAR" value="PRODUCER 1"/>
<PUBLICATION_CODE_-_NAME type="VARCHAR" value="PUBLICATION B"/>
<DOMESTIC type="DECIMAL" value="57"/>
<FOREIGN type="DECIMAL" value="10"/>
</row>
<row>
<PRODUCER type="VARCHAR" value="PRODUCER 2"/>
<PUBLICATION_CODE_-_NAME type="VARCHAR" value="PUBLICATION C"/>
<DOMESTIC type="DECIMAL" value="35"/>
<FOREIGN type="DECIMAL" value="20"/>
</row>
<row>
<PRODUCER type="VARCHAR" value="PRODUCER 2"/>
<PUBLICATION_CODE_-_NAME type="VARCHAR" value="PUBLICATION D"/>
<DOMESTIC type="DECIMAL" value="23"/>
<FOREIGN type="DECIMAL" value="18"/>
</row>
</table>
到目前为止,我已经能够实现我希望的一切,除了根据生产者获得国内和国外的总和。我已经阅读了 Muenchian 分组等内容,但我无法将其应用于我的 XML。我相信我必须创建一个基于 PRODUCER 的密钥,如下所示。
<xsl:key name="producerkey" match="/table/row/" use="PRODUCER/@value"/>
正是在这一点上,我 运行 遇到了一个问题。我相信我必须生成 ID 并使用这些 ID 对我的值进行分组。
到目前为止,我能够生成与此类似的 PDF。
| PRODUCER || PUBLICATION ||DOMESTIC||FOREIGN|
------------------------------------------
|PRODUCER 1||PUBLICATION A|| 20 || 4 |
| ||PUBLICATION B|| 57 || 10 |
| ||TOTALS || DTOTAL || FTOTAL|
|PRODUCER 2||PUBLICATION C|| 35 || 20 |
| ||PUBLICATION D|| 23 || 18 |
| ||TOTALS || DTOTAL || FTOTAL|
我正在尝试用适当的 PRODUCER 分组将 DOMESTIC 和 FOREIGN 列的总和替换 "DTOTAL" 和 "FTOTAL"。
以下是我认为我们工作的 XSLT 中最相关的部分,它生成的布局类似于上面的 table。
<xsl:template match="row">
<fo:table>
<fo:table-body font-size="10pt"
font-family="sans-serif"
line-height="10pt"
space-after.optimum="3pt">
<xsl:for-each select="current()">
<xsl:variable name="testnext" select="following-sibling::*[1]"/>
<xsl:choose>
<xsl:when test="$testnext">
<xsl:choose>
<xsl:when test="$testnext/PRODUCER/@value = child::PRODUCER/@value">
<fo:table-row>
<xsl:apply-templates select="PRODUCER"/>
<xsl:apply-templates select="PUBLICATION_CODE_-_NAME"/>
<xsl:apply-templates select="DOMESTIC"/>
<xsl:apply-templates select="FOREIGN"/>
</fo:table-row>
</xsl:when>
<xsl:otherwise>
<fo:table-row>
<xsl:apply-templates select="PRODUCER"/>
<xsl:apply-templates select="PUBLICATION_CODE_-_NAME"/>
<xsl:apply-templates select="DOMESTIC"/>
<xsl:apply-templates select="FOREIGN"/>
</fo:table-row>
<fo:table-row>
<fo:table-cell width="2.125in"
height="0.4in">
<fo:block>
<fo:leader/>
</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in"
height="0.4in">
<fo:block>
PRODUCER TOTAL
</fo:block>
</fo:table-cell>
<fo:table-cell width="0.95in"
height="0.4in">
<fo:block>
DTOTAL
</fo:block>
</fo:table-cell>
<fo:table-cell width="0.95in"
height="0.4in">
<fo:block>
FTOTAL
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<fo:table-row>
<xsl:apply-templates select="PRODUCER"/>
<xsl:apply-templates select="PUBLICATION_CODE_-_NAME"/>
<xsl:apply-templates select="DOMESTIC"/>
<xsl:apply-templates select="FOREIGN"/>
</fo:table-row>
<fo:table-row>
<fo:table-cell width="2.125in"
height="0.4in">
<fo:block>
<fo:leader/>
</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in"
height="0.4in">
<fo:block>
PRODUCER TOTAL
</fo:block>
</fo:table-cell>
<fo:table-cell width="0.95in"
height="0.4in">
<fo:block>
DTOTAL
</fo:block>
</fo:table-cell>
<fo:table-cell width="0.95in"
height="0.4in">
<fo:block>
FTOTAL
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</fo:table-body>
</fo:table>
</xsl:template>
<xsl:template match="PRODUCER">
<fo:table-cell width="2.125in"
height="0.2in">
<fo:block>
<xsl:variable name="test" select="parent::row/preceding-sibling::row[1]"/>
<xsl:choose>
<xsl:when test="$test">
<xsl:choose>
<xsl:when test="$test/PRODUCER/@value = @value">
<fo:leader/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@value"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@value"/>
</xsl:otherwise>
</xsl:choose>
</fo:block>
</fo:table-cell>
</xsl:template>
<xsl:template match="PUBLICATION_CODE_-_NAME">
<fo:table-cell width="3.25in"
height="0.2in">
<fo:block>
<xsl:value-of select="@value"/>
</fo:block>
</fo:table-cell>
</xsl:template>
<xsl:template match="DOMESTIC">
<fo:table-cell width="0.95in"
height="0.2in">
<fo:block>
<xsl:value-of select="@value"/>
</fo:block>
</fo:table-cell>
</xsl:template>
<xsl:template match="FOREIGN">
<fo:table-cell width="0.95in"
height="0.2in">
<fo:block>
<xsl:value-of select="@value"/>
</fo:block>
</fo:table-cell>
</xsl:template>
我正在做的事情的基础是检查每一行的 PRODUCER 并使用该比较来确定何时在第一列中包含 PRODUCER 值以及何时创建包含列总和的行以及额外的 space。我确定我的代码有点乱,但我刚刚开始使用这项技术,发现学习曲线对于自学来说有点陡峭。此外,如果它是第一行,则包含 PRODUCER,如果它是最后一行,则将在旁边包含总计行以完成报告。对于它的价值,生产者已经按照适当的顺序分组。
所有 help/advice/criticism 将不胜感激。
这在 XSLT 2 中要容易得多,但为了过去:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="producerkey" match="row" use="PRODUCER/@value"/>
<xsl:template match="table">
<table>
<thead>
<tr>
<th>Producer</th>
<th>Publication</th>
<th>Domestic</th>
<th>Foreigh</th>
</tr>
</thead>
<tbody>
<xsl:for-each select="row[
generate-id(.)
=
generate-id(key('producerkey',PRODUCER/@value))[1]
]">
<xsl:for-each select="key('producerkey',PRODUCER/@value)">
<tr>
<td>-
<xsl:if test="position()=1">
<xsl:value-of select="PRODUCER/@value"/>
</xsl:if>
</td>
<td><xsl:value-of select="PUBLICATION_CODE_-_NAME/@value"/></td>
<td><xsl:value-of select="DOMESTIC/@value"/></td>
<td><xsl:value-of select="FOREIGN/@value"/></td>
</tr>
</xsl:for-each>
<tr>
<td>-</td>
<td>Totals</td>
<td><xsl:value-of select="sum(key('producerkey',PRODUCER/@value)/DOMESTIC/@value)"/></td>
<td><xsl:value-of select="sum(key('producerkey',PRODUCER/@value)/FOREIGN/@value)"/></td>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
</xsl:stylesheet>
生产
<table><thead>
<tr><th>Producer</th><th>Publication</th><th>Domestic</th><th>Foreigh</th></tr></thead><tbody>
<tr>
<td>-PRODUCER 1</td><td>PUBLICATION A</td><td>20</td><td>4</td></tr>
<tr><td>-</td><td>PUBLICATION B</td><td>57</td><td>10</td></tr>
<tr><td>-</td><td>Totals</td><td>77</td><td>14</td></tr>
<tr><td>-
PRODUCER 2</td><td>PUBLICATION C</td><td>35</td><td>20</td></tr>
<tr><td>-</td><td>PUBLICATION D</td><td>23</td><td>18</td></tr>
<tr><td>-</td><td>Totals</td><td>58</td><td>38</td></tr>
</tbody>
</table>
我目前正在尝试使用 XSLT 1.0 中的分组。我有 XML 与此类似:
<table>
<row>
<PRODUCER type="VARCHAR" value="PRODUCER 1"/>
<PUBLICATION_CODE_-_NAME type="VARCHAR" value="PUBLICATION A"/>
<DOMESTIC type="DECIMAL" value="20"/>
<FOREIGN type="DECIMAL" value="4"/>
</row>
<row>
<PRODUCER type="VARCHAR" value="PRODUCER 1"/>
<PUBLICATION_CODE_-_NAME type="VARCHAR" value="PUBLICATION B"/>
<DOMESTIC type="DECIMAL" value="57"/>
<FOREIGN type="DECIMAL" value="10"/>
</row>
<row>
<PRODUCER type="VARCHAR" value="PRODUCER 2"/>
<PUBLICATION_CODE_-_NAME type="VARCHAR" value="PUBLICATION C"/>
<DOMESTIC type="DECIMAL" value="35"/>
<FOREIGN type="DECIMAL" value="20"/>
</row>
<row>
<PRODUCER type="VARCHAR" value="PRODUCER 2"/>
<PUBLICATION_CODE_-_NAME type="VARCHAR" value="PUBLICATION D"/>
<DOMESTIC type="DECIMAL" value="23"/>
<FOREIGN type="DECIMAL" value="18"/>
</row>
</table>
到目前为止,我已经能够实现我希望的一切,除了根据生产者获得国内和国外的总和。我已经阅读了 Muenchian 分组等内容,但我无法将其应用于我的 XML。我相信我必须创建一个基于 PRODUCER 的密钥,如下所示。
<xsl:key name="producerkey" match="/table/row/" use="PRODUCER/@value"/>
正是在这一点上,我 运行 遇到了一个问题。我相信我必须生成 ID 并使用这些 ID 对我的值进行分组。
到目前为止,我能够生成与此类似的 PDF。
| PRODUCER || PUBLICATION ||DOMESTIC||FOREIGN|
------------------------------------------
|PRODUCER 1||PUBLICATION A|| 20 || 4 |
| ||PUBLICATION B|| 57 || 10 |
| ||TOTALS || DTOTAL || FTOTAL|
|PRODUCER 2||PUBLICATION C|| 35 || 20 |
| ||PUBLICATION D|| 23 || 18 |
| ||TOTALS || DTOTAL || FTOTAL|
我正在尝试用适当的 PRODUCER 分组将 DOMESTIC 和 FOREIGN 列的总和替换 "DTOTAL" 和 "FTOTAL"。
以下是我认为我们工作的 XSLT 中最相关的部分,它生成的布局类似于上面的 table。
<xsl:template match="row">
<fo:table>
<fo:table-body font-size="10pt"
font-family="sans-serif"
line-height="10pt"
space-after.optimum="3pt">
<xsl:for-each select="current()">
<xsl:variable name="testnext" select="following-sibling::*[1]"/>
<xsl:choose>
<xsl:when test="$testnext">
<xsl:choose>
<xsl:when test="$testnext/PRODUCER/@value = child::PRODUCER/@value">
<fo:table-row>
<xsl:apply-templates select="PRODUCER"/>
<xsl:apply-templates select="PUBLICATION_CODE_-_NAME"/>
<xsl:apply-templates select="DOMESTIC"/>
<xsl:apply-templates select="FOREIGN"/>
</fo:table-row>
</xsl:when>
<xsl:otherwise>
<fo:table-row>
<xsl:apply-templates select="PRODUCER"/>
<xsl:apply-templates select="PUBLICATION_CODE_-_NAME"/>
<xsl:apply-templates select="DOMESTIC"/>
<xsl:apply-templates select="FOREIGN"/>
</fo:table-row>
<fo:table-row>
<fo:table-cell width="2.125in"
height="0.4in">
<fo:block>
<fo:leader/>
</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in"
height="0.4in">
<fo:block>
PRODUCER TOTAL
</fo:block>
</fo:table-cell>
<fo:table-cell width="0.95in"
height="0.4in">
<fo:block>
DTOTAL
</fo:block>
</fo:table-cell>
<fo:table-cell width="0.95in"
height="0.4in">
<fo:block>
FTOTAL
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<fo:table-row>
<xsl:apply-templates select="PRODUCER"/>
<xsl:apply-templates select="PUBLICATION_CODE_-_NAME"/>
<xsl:apply-templates select="DOMESTIC"/>
<xsl:apply-templates select="FOREIGN"/>
</fo:table-row>
<fo:table-row>
<fo:table-cell width="2.125in"
height="0.4in">
<fo:block>
<fo:leader/>
</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in"
height="0.4in">
<fo:block>
PRODUCER TOTAL
</fo:block>
</fo:table-cell>
<fo:table-cell width="0.95in"
height="0.4in">
<fo:block>
DTOTAL
</fo:block>
</fo:table-cell>
<fo:table-cell width="0.95in"
height="0.4in">
<fo:block>
FTOTAL
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</fo:table-body>
</fo:table>
</xsl:template>
<xsl:template match="PRODUCER">
<fo:table-cell width="2.125in"
height="0.2in">
<fo:block>
<xsl:variable name="test" select="parent::row/preceding-sibling::row[1]"/>
<xsl:choose>
<xsl:when test="$test">
<xsl:choose>
<xsl:when test="$test/PRODUCER/@value = @value">
<fo:leader/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@value"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@value"/>
</xsl:otherwise>
</xsl:choose>
</fo:block>
</fo:table-cell>
</xsl:template>
<xsl:template match="PUBLICATION_CODE_-_NAME">
<fo:table-cell width="3.25in"
height="0.2in">
<fo:block>
<xsl:value-of select="@value"/>
</fo:block>
</fo:table-cell>
</xsl:template>
<xsl:template match="DOMESTIC">
<fo:table-cell width="0.95in"
height="0.2in">
<fo:block>
<xsl:value-of select="@value"/>
</fo:block>
</fo:table-cell>
</xsl:template>
<xsl:template match="FOREIGN">
<fo:table-cell width="0.95in"
height="0.2in">
<fo:block>
<xsl:value-of select="@value"/>
</fo:block>
</fo:table-cell>
</xsl:template>
我正在做的事情的基础是检查每一行的 PRODUCER 并使用该比较来确定何时在第一列中包含 PRODUCER 值以及何时创建包含列总和的行以及额外的 space。我确定我的代码有点乱,但我刚刚开始使用这项技术,发现学习曲线对于自学来说有点陡峭。此外,如果它是第一行,则包含 PRODUCER,如果它是最后一行,则将在旁边包含总计行以完成报告。对于它的价值,生产者已经按照适当的顺序分组。
所有 help/advice/criticism 将不胜感激。
这在 XSLT 2 中要容易得多,但为了过去:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="producerkey" match="row" use="PRODUCER/@value"/>
<xsl:template match="table">
<table>
<thead>
<tr>
<th>Producer</th>
<th>Publication</th>
<th>Domestic</th>
<th>Foreigh</th>
</tr>
</thead>
<tbody>
<xsl:for-each select="row[
generate-id(.)
=
generate-id(key('producerkey',PRODUCER/@value))[1]
]">
<xsl:for-each select="key('producerkey',PRODUCER/@value)">
<tr>
<td>-
<xsl:if test="position()=1">
<xsl:value-of select="PRODUCER/@value"/>
</xsl:if>
</td>
<td><xsl:value-of select="PUBLICATION_CODE_-_NAME/@value"/></td>
<td><xsl:value-of select="DOMESTIC/@value"/></td>
<td><xsl:value-of select="FOREIGN/@value"/></td>
</tr>
</xsl:for-each>
<tr>
<td>-</td>
<td>Totals</td>
<td><xsl:value-of select="sum(key('producerkey',PRODUCER/@value)/DOMESTIC/@value)"/></td>
<td><xsl:value-of select="sum(key('producerkey',PRODUCER/@value)/FOREIGN/@value)"/></td>
</tr>
</xsl:for-each>
</tbody>
</table>
</xsl:template>
</xsl:stylesheet>
生产
<table><thead>
<tr><th>Producer</th><th>Publication</th><th>Domestic</th><th>Foreigh</th></tr></thead><tbody>
<tr>
<td>-PRODUCER 1</td><td>PUBLICATION A</td><td>20</td><td>4</td></tr>
<tr><td>-</td><td>PUBLICATION B</td><td>57</td><td>10</td></tr>
<tr><td>-</td><td>Totals</td><td>77</td><td>14</td></tr>
<tr><td>-
PRODUCER 2</td><td>PUBLICATION C</td><td>35</td><td>20</td></tr>
<tr><td>-</td><td>PUBLICATION D</td><td>23</td><td>18</td></tr>
<tr><td>-</td><td>Totals</td><td>58</td><td>38</td></tr>
</tbody>
</table>