XSL FO Table 中的粗边框问题 - 使用 Apache FOP 创建 PDF
Thick border line issue in XSL FO Table - PDF Creation Using Apache FOP
我试图根据 Web 应用程序的要求隐藏 fo:table 行或列行,所以我过去常常将 border-style="none"
设置为 fo:table-column
或 fo:table-row
根据需要,但当我尝试时,
要么在行中创建暗线(如果我隐藏列线)
或在列中创建暗线(如果我隐藏行线)。
如果列行被隐藏:
如果行线被隐藏:
我的 XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="pages">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simple"
page-height="8.5in" page-width="11in" margin-top=".5in"
margin-bottom=".5in" margin-left=".5in" margin-right=".5in">
<fo:region-body margin-top="2cm" margin-bottom="2cm" />
<fo:region-before extent="2cm" overflow="hidden" />
<fo:region-after extent="1cm" overflow="hidden" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simple"
initial-page-number="1">
<fo:static-content flow-name="xsl-region-before">
<fo:block font-size="13.0pt" font-family="serif"
padding-after="2.0pt" space-before="4.0pt" text-align="center"
border-bottom-style="solid" border-bottom-width="1.0pt">
<fo:block>IF COLUMN LINES HIDED</fo:block>
</fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-region-after">
<fo:block font-size="12.0pt" font-family="sans-serif"
padding-after="2.0pt" space-before="2.0pt" text-align="center"
border-top-style="solid" border-bottom-width="1.0pt">
<xsl:text>Page</xsl:text>
<fo:page-number />
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<xsl:apply-templates select="page-body" />
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="page-body">
<fo:block text-align="center" break-before="page">
<fo:table table-layout="fixed" width="100%"
border-style="solid">
<fo:table-column border-style="solid"/>
<fo:table-column border-style="solid"/>
<fo:table-column border-style="solid"/>
<!-- For hiding column lines -->
<!-- <fo:table-column border-style="none"/> -->
<!-- <fo:table-column border-style="none"/> -->
<!-- <fo:table-column border-style="none"/> -->
<fo:table-header>
<xsl:apply-templates select="table-header" />
</fo:table-header>
<fo:table-body>
<xsl:apply-templates select="table-data" />
</fo:table-body>
</fo:table>
</fo:block>
</xsl:template>
<xsl:template match="table-header">
<fo:table-row keep-together.within-page="always"
border-style="solid">
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="column-one"></xsl:value-of>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="column-two"></xsl:value-of>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="column-three"></xsl:value-of>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:template>
<xsl:template match="table-data">
<fo:table-row keep-together.within-page="always"
border-style="none">
<!-- For showing row lines -->
<!-- <fo:table-row keep-together.within-page="always" -->
<!-- border-style="solid"> -->
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="column-one"></xsl:value-of>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:if test="number(column-two) = number(column-two)">
<xsl:value-of select="format-number(translate(column-two, ',','.'), '#,###.##')"></xsl:value-of>
</xsl:if>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="column-three"></xsl:value-of>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:template>
</xsl:stylesheet>
我的XML:
<?xml version="1.0" encoding="UTF-8"?>
<pages>
<page-body>
<table-header>
<column-one>Column One</column-one>
<column-two>Column Two</column-two>
<column-three>Column Three</column-three>
</table-header>
<table-data>
<column-one>One</column-one>
<column-two>5000</column-two>
<column-three>Three</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>5000</column-two>
<column-three>Three</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>0</column-two>
<column-three>Three</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>0</column-two>
<column-three>Four</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>2000</column-two>
<column-three>Four</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>1234</column-two>
<column-three>Five</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>5666</column-two>
<column-three>Five</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>5666</column-two>
<column-three>Five</column-three>
</table-data>
</page-body>
</pages>
我正在使用这些 xml 和 xsl 文件通过 apache fop 生成 PDF,我的代码有什么问题吗?
不幸的是,在涉及 FOP 渲染的 FO 开发中时常会出现这种情况。
您的答案,请参阅Section 6.9 of xmlgraphics.apache.org's FAQ re anti-aliasing and Acrobat。
请注意,如果您在 Acrobat 中使用缩放系数,问题将 disappear/reappear 取决于设置。
另请注意,如果您使用 RenderX (a.k.a XEP) 尝试示例,则不会发生这种情况。他们显然已经解决了(或从未解决过)问题。
试图摆脱非商业 FO 产品的危险之一。 (当然,并不是说某些东西一定要商业化才好,但这只是事实,即商业 FO 处理器比 FOP 更好、更强大,尽管 FOP 正在改进,尽管速度很慢。)
如果您必须继续使用 FOP,请确保您使用的是最新版本(请参阅此 pin)。 2.4 的一些重要好处。
附录(SVG 的使用):
您可以通过动态构建的 SVG 标记来避免这种 FOP 错误。
这是您必须生成的标记类型的示例,才能通过此方法获取 PDF table:
<fo:instream-foreign-object>
<svg:svg width="1000%" height="1000%">
<svg:g id='rowGroup' transform='translate(0, 0)' role="table">
<svg:text x='30' y='30' font-size='18px' font-weight='bold' fill='crimson' text-anchor='middle' role="row">
<svg:tspan role="columnheader" x='100'>Sales</svg:tspan>
<svg:tspan role="columnheader" x='200'>Expenses</svg:tspan>
<svg:tspan role="columnheader" x='300'>Net</svg:tspan>
</svg:text>
<svg:rect x='30' y='40' width='310' height='1' fill='black'/>
<svg:text x='30' y='30' font-size='18px' text-anchor='middle' role="row">
<svg:tspan id="q1" role="rowheader" x='30' dy='1.5em' font-weight='bold' fill='crimson' text-anchor='start'>Q1</svg:tspan>
<svg:tspan role="cell" x='100'>3</svg:tspan>
<svg:tspan role="cell" x='200'>5</svg:tspan>
<svg:tspan role="cell" x='300'></svg:tspan>
</svg:text>
<svg:rect x='30' y='60' width='310' height='1' fill='black'/>
<svg:text x='30' y='50' font-size='18px' text-anchor='middle' role="row">
<svg:tspan id="q2" role="rowheader" x='30' dy='1.5em' font-weight='bold' fill='crimson' text-anchor='start'>Q2</svg:tspan>
<svg:tspan role="cell" x='100'>5</svg:tspan>
<svg:tspan role="cell" x='200'>3</svg:tspan>
<svg:tspan role="cell" x='300'></svg:tspan>
</svg:text>
<svg:rect x='30' y='80' width='310' height='1' fill='black'/>
<svg:text x='30' y='70' font-size='18px' text-anchor='middle' role="row">
<svg:tspan id="q3" role="rowheader" x='30' dy='1.5em' font-weight='bold' fill='crimson' text-anchor='start'>Q3</svg:tspan>
<svg:tspan role="cell" x='100'>1</svg:tspan>
<svg:tspan role="cell" x='200'>2</svg:tspan>
<svg:tspan role="cell" x='300'>9</svg:tspan>
</svg:text>
<svg:rect x='30' y='100' width='310' height='1' fill='black'/>
<svg:text x='30' y='90' font-size='18px' text-anchor='middle' role="row">
<svg:tspan id="q4" role="rowheader" x='30' dy='1.5em' font-weight='bold' fill='crimson' text-anchor='start'>Q4</svg:tspan>
<svg:tspan role="cell" x='100'>3</svg:tspan>
<svg:tspan role="cell" x='200'>5</svg:tspan>
<svg:tspan role="cell" x='300'>8</svg:tspan>
</svg:text>
<svg:rect x='30' y='120' width='310' height='1' fill='black'/>
</svg:g>
</svg:svg>
</fo:instream-foreign-object>
我留给您为您的特定情况动态创建 FO,但这应该会教您如何以这种方式构建 tables。
您可以通过将边框绘制为 SVG 多边形 来轻松实现您想要的效果,这就是 Kevin 的目的(尽管我相信他说的是里面的代码RenderX 引擎。我的解决方案通过嵌入式 SVG 创建将其外部化。)当然,<svg:rect>
标签是多边形的一种形式,这就是您用来呈现边框的内容。
如果您要尝试此操作,请记住在您的 <xsl:stylesheet>
标签上指定 SVG 命名空间。
xmlns:svg="http://www.w3.org/2000/svg"
查看这个最近合并的补丁(合并于 2020-12-29),它似乎为我解决了这个问题:
https://issues.apache.org/jira/browse/FOP-2536(在 PDF 输出中改变 table 边框粗细)
修订版 1884907:FOP-2536:允许重绘 PDF 边框
从 Apache FOP 2.6 开始,您可以在配置文件中设置以下参数(默认 fop.xconf):
<table-border-overpaint>true</table-border-overpaint>
此选项可能会使您的边框变粗,但可以解决一个问题:
https://xmlgraphics.apache.org/fop/faq.html#acrobat-anti-aliasing
此外,此问题已注册为 Chromium Pdf 渲染错误:
https://bugs.chromium.org/p/chromium/issues/detail?id=500023
我试图根据 Web 应用程序的要求隐藏 fo:table 行或列行,所以我过去常常将 border-style="none"
设置为 fo:table-column
或 fo:table-row
根据需要,但当我尝试时,
要么在行中创建暗线(如果我隐藏列线)
或在列中创建暗线(如果我隐藏行线)。
如果列行被隐藏:
如果行线被隐藏:
我的 XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="pages">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="simple"
page-height="8.5in" page-width="11in" margin-top=".5in"
margin-bottom=".5in" margin-left=".5in" margin-right=".5in">
<fo:region-body margin-top="2cm" margin-bottom="2cm" />
<fo:region-before extent="2cm" overflow="hidden" />
<fo:region-after extent="1cm" overflow="hidden" />
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="simple"
initial-page-number="1">
<fo:static-content flow-name="xsl-region-before">
<fo:block font-size="13.0pt" font-family="serif"
padding-after="2.0pt" space-before="4.0pt" text-align="center"
border-bottom-style="solid" border-bottom-width="1.0pt">
<fo:block>IF COLUMN LINES HIDED</fo:block>
</fo:block>
</fo:static-content>
<fo:static-content flow-name="xsl-region-after">
<fo:block font-size="12.0pt" font-family="sans-serif"
padding-after="2.0pt" space-before="2.0pt" text-align="center"
border-top-style="solid" border-bottom-width="1.0pt">
<xsl:text>Page</xsl:text>
<fo:page-number />
</fo:block>
</fo:static-content>
<fo:flow flow-name="xsl-region-body">
<xsl:apply-templates select="page-body" />
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="page-body">
<fo:block text-align="center" break-before="page">
<fo:table table-layout="fixed" width="100%"
border-style="solid">
<fo:table-column border-style="solid"/>
<fo:table-column border-style="solid"/>
<fo:table-column border-style="solid"/>
<!-- For hiding column lines -->
<!-- <fo:table-column border-style="none"/> -->
<!-- <fo:table-column border-style="none"/> -->
<!-- <fo:table-column border-style="none"/> -->
<fo:table-header>
<xsl:apply-templates select="table-header" />
</fo:table-header>
<fo:table-body>
<xsl:apply-templates select="table-data" />
</fo:table-body>
</fo:table>
</fo:block>
</xsl:template>
<xsl:template match="table-header">
<fo:table-row keep-together.within-page="always"
border-style="solid">
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="column-one"></xsl:value-of>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="column-two"></xsl:value-of>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="column-three"></xsl:value-of>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:template>
<xsl:template match="table-data">
<fo:table-row keep-together.within-page="always"
border-style="none">
<!-- For showing row lines -->
<!-- <fo:table-row keep-together.within-page="always" -->
<!-- border-style="solid"> -->
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="column-one"></xsl:value-of>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:if test="number(column-two) = number(column-two)">
<xsl:value-of select="format-number(translate(column-two, ',','.'), '#,###.##')"></xsl:value-of>
</xsl:if>
</fo:block>
</fo:table-cell>
<fo:table-cell>
<fo:block font-size="10pt" font-family="sans-serif"
padding-top="3pt">
<xsl:value-of select="column-three"></xsl:value-of>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:template>
</xsl:stylesheet>
我的XML:
<?xml version="1.0" encoding="UTF-8"?>
<pages>
<page-body>
<table-header>
<column-one>Column One</column-one>
<column-two>Column Two</column-two>
<column-three>Column Three</column-three>
</table-header>
<table-data>
<column-one>One</column-one>
<column-two>5000</column-two>
<column-three>Three</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>5000</column-two>
<column-three>Three</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>0</column-two>
<column-three>Three</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>0</column-two>
<column-three>Four</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>2000</column-two>
<column-three>Four</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>1234</column-two>
<column-three>Five</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>5666</column-two>
<column-three>Five</column-three>
</table-data>
<table-data>
<column-one>One</column-one>
<column-two>5666</column-two>
<column-three>Five</column-three>
</table-data>
</page-body>
</pages>
我正在使用这些 xml 和 xsl 文件通过 apache fop 生成 PDF,我的代码有什么问题吗?
不幸的是,在涉及 FOP 渲染的 FO 开发中时常会出现这种情况。
您的答案,请参阅Section 6.9 of xmlgraphics.apache.org's FAQ re anti-aliasing and Acrobat。
请注意,如果您在 Acrobat 中使用缩放系数,问题将 disappear/reappear 取决于设置。
另请注意,如果您使用 RenderX (a.k.a XEP) 尝试示例,则不会发生这种情况。他们显然已经解决了(或从未解决过)问题。
试图摆脱非商业 FO 产品的危险之一。 (当然,并不是说某些东西一定要商业化才好,但这只是事实,即商业 FO 处理器比 FOP 更好、更强大,尽管 FOP 正在改进,尽管速度很慢。)
如果您必须继续使用 FOP,请确保您使用的是最新版本(请参阅此 pin)。 2.4 的一些重要好处。
附录(SVG 的使用):
您可以通过动态构建的 SVG 标记来避免这种 FOP 错误。
这是您必须生成的标记类型的示例,才能通过此方法获取 PDF table:
<fo:instream-foreign-object>
<svg:svg width="1000%" height="1000%">
<svg:g id='rowGroup' transform='translate(0, 0)' role="table">
<svg:text x='30' y='30' font-size='18px' font-weight='bold' fill='crimson' text-anchor='middle' role="row">
<svg:tspan role="columnheader" x='100'>Sales</svg:tspan>
<svg:tspan role="columnheader" x='200'>Expenses</svg:tspan>
<svg:tspan role="columnheader" x='300'>Net</svg:tspan>
</svg:text>
<svg:rect x='30' y='40' width='310' height='1' fill='black'/>
<svg:text x='30' y='30' font-size='18px' text-anchor='middle' role="row">
<svg:tspan id="q1" role="rowheader" x='30' dy='1.5em' font-weight='bold' fill='crimson' text-anchor='start'>Q1</svg:tspan>
<svg:tspan role="cell" x='100'>3</svg:tspan>
<svg:tspan role="cell" x='200'>5</svg:tspan>
<svg:tspan role="cell" x='300'></svg:tspan>
</svg:text>
<svg:rect x='30' y='60' width='310' height='1' fill='black'/>
<svg:text x='30' y='50' font-size='18px' text-anchor='middle' role="row">
<svg:tspan id="q2" role="rowheader" x='30' dy='1.5em' font-weight='bold' fill='crimson' text-anchor='start'>Q2</svg:tspan>
<svg:tspan role="cell" x='100'>5</svg:tspan>
<svg:tspan role="cell" x='200'>3</svg:tspan>
<svg:tspan role="cell" x='300'></svg:tspan>
</svg:text>
<svg:rect x='30' y='80' width='310' height='1' fill='black'/>
<svg:text x='30' y='70' font-size='18px' text-anchor='middle' role="row">
<svg:tspan id="q3" role="rowheader" x='30' dy='1.5em' font-weight='bold' fill='crimson' text-anchor='start'>Q3</svg:tspan>
<svg:tspan role="cell" x='100'>1</svg:tspan>
<svg:tspan role="cell" x='200'>2</svg:tspan>
<svg:tspan role="cell" x='300'>9</svg:tspan>
</svg:text>
<svg:rect x='30' y='100' width='310' height='1' fill='black'/>
<svg:text x='30' y='90' font-size='18px' text-anchor='middle' role="row">
<svg:tspan id="q4" role="rowheader" x='30' dy='1.5em' font-weight='bold' fill='crimson' text-anchor='start'>Q4</svg:tspan>
<svg:tspan role="cell" x='100'>3</svg:tspan>
<svg:tspan role="cell" x='200'>5</svg:tspan>
<svg:tspan role="cell" x='300'>8</svg:tspan>
</svg:text>
<svg:rect x='30' y='120' width='310' height='1' fill='black'/>
</svg:g>
</svg:svg>
</fo:instream-foreign-object>
我留给您为您的特定情况动态创建 FO,但这应该会教您如何以这种方式构建 tables。
您可以通过将边框绘制为 SVG 多边形 来轻松实现您想要的效果,这就是 Kevin 的目的(尽管我相信他说的是里面的代码RenderX 引擎。我的解决方案通过嵌入式 SVG 创建将其外部化。)当然,<svg:rect>
标签是多边形的一种形式,这就是您用来呈现边框的内容。
如果您要尝试此操作,请记住在您的 <xsl:stylesheet>
标签上指定 SVG 命名空间。
xmlns:svg="http://www.w3.org/2000/svg"
查看这个最近合并的补丁(合并于 2020-12-29),它似乎为我解决了这个问题:
https://issues.apache.org/jira/browse/FOP-2536(在 PDF 输出中改变 table 边框粗细)
修订版 1884907:FOP-2536:允许重绘 PDF 边框
从 Apache FOP 2.6 开始,您可以在配置文件中设置以下参数(默认 fop.xconf):
<table-border-overpaint>true</table-border-overpaint>
此选项可能会使您的边框变粗,但可以解决一个问题: https://xmlgraphics.apache.org/fop/faq.html#acrobat-anti-aliasing
此外,此问题已注册为 Chromium Pdf 渲染错误: https://bugs.chromium.org/p/chromium/issues/detail?id=500023