如何使用XSL-FO生成PDF格式的电子发票的技术博文示例

目录

      • [使用 XSL-FO 生成电子发票 PDF:从布局设计到优化](#使用 XSL-FO 生成电子发票 PDF:从布局设计到优化)
        • [为什么选择 XSL-FO?](#为什么选择 XSL-FO?)
        • [1. 初始设置](#1. 初始设置)
        • [2. 标题区块](#2. 标题区块)
        • [3. 买卖方信息](#3. 买卖方信息)
        • [4. 商品明细表格](#4. 商品明细表格)
        • [5. 合计信息](#5. 合计信息)
        • [6. 优化代码结构与布局](#6. 优化代码结构与布局)
        • [7. 生成 PDF 文件](#7. 生成 PDF 文件)
        • [8. 示例](#8. 示例)
        • 总结

使用 XSL-FO 生成电子发票 PDF:从布局设计到优化

在电子商务和财务系统中,生成规范化的发票 PDF 文件是一个常见需求。利用 XSL-FO(Extensible Stylesheet Language Formatting Objects),我们可以设计和生成格式规范的发票 PDF。本文将介绍如何使用 XSL-FO 构建电子发票的 PDF 文件,并提供一些优化布局的建议,以实现更清晰美观的发票。

为什么选择 XSL-FO?

XSL-FO 是 W3C 的标准,用于将 XML 文档格式化为 PDF、PostScript 等格式的高质量输出文档。它尤其适合结构化数据的排版需求。结合 Apache FOP(Formatting Objects Processor)等工具,我们可以从 XML 模板生成发票 PDF。

1. 初始设置

首先,在根节点 <fo:root> 中设置页面布局:

xml 复制代码
<fo:layout-master-set>
    <fo:simple-page-master master-name="invoice">
        <fo:region-body margin="5mm"/>
    </fo:simple-page-master>
</fo:layout-master-set>

这里指定了页面的边距和布局,便于后续的内容排版。

2. 标题区块

发票的顶部通常包含发票标题、二维码、公司信息和发票号。可以通过 <fo:table> 元素来布局这些信息,利用列宽度来控制内容的对齐和分布:

xml 复制代码
<fo:table table-layout="fixed" width="100%">
    <fo:table-column column-width="22%"/>
    <fo:table-column column-width="56%"/>
    <fo:table-column column-width="22%"/>
    ...
</fo:table>

在这个表格中,我们在左右两侧显示二维码和发票信息,中间展示发票标题。通过设置 column-width,可以确保不同元素之间的布局合理。

3. 买卖方信息

发票中买方和卖方的信息是关键内容。我们使用 <fo:table> 元素创建一个两列的表格来放置这些信息:

xml 复制代码
<fo:table-column column-width="5%"/>
<fo:table-column column-width="45%"/>

每个列块中包括公司名称、税号等信息,并使用 writing-mode="tb-rl" 为标签列设置垂直方向书写,从而增强布局的清晰度。

4. 商品明细表格

商品明细表格包含了商品的名称、规格、单位、数量、单价、金额、税率、税额等。可以通过固定列宽设置,确保不同商品数据的显示一致:

xml 复制代码
<fo:table-column column-width="20%"/>
...

对于每个商品的明细行,我们使用了 fo:table-body 标签,包含具体的内容。可以进一步通过 min-height="50pt" 设置行高度,确保无数据时也有足够的空间。

5. 合计信息

在表格的下方,使用一个新的表格展示"价税合计"信息,包括大小写金额:

xml 复制代码
<fo:table-body>
    <fo:table-row>
        <fo:table-cell text-align="center"><fo:block>价税合计(大写)</fo:block></fo:table-cell>
        ...
    </fo:table-row>
</fo:table-body>

通过将列宽和内容对齐调整为居中,可以确保整体布局对齐美观。

6. 优化代码结构与布局

在发票生成过程中,统一样式设置和简化代码结构可以提高代码的可读性和可维护性,以下是几点优化建议:

  • 统一表格样式:将表格边框样式、颜色等属性集中设置,避免重复代码。
  • 简化内容布局 :对于标签文本等内容,使用 writing-mode="tb-rl" 实现垂直对齐,避免复杂的布局调整。
  • 表格布局的合理分配 :使用 table-layout="fixed" 和精确的 column-width 设置,确保表格布局稳定。
7. 生成 PDF 文件

在完成 XSL-FO 模板后,可以使用 Apache FOP 工具将其转换为 PDF 文件:

bash 复制代码
fop -xml invoice.xml -xsl invoice.xsl -pdf invoice.pdf

这样即可获得一份规范、清晰的电子发票 PDF 文件。

8. 示例
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
         xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"
         xmlns:xe="http://www.x-easypdf.cn/ns"
         xmlns:svg="http://www.w3.org/2000/svg">
    <fo:layout-master-set>
            <fo:simple-page-master master-name="invoice">
                <fo:region-body margin="5mm"/>
            </fo:simple-page-master>
        </fo:layout-master-set>

        <fo:page-sequence master-reference="invoice">
            <fo:flow flow-name="xsl-region-body" color="rgb(188, 119, 76)">

                <fo:block font-family="SimSun" space-before="10pt">
                    <fo:table table-layout="fixed" width="100%">
                        <fo:table-column column-width="22%"/>
                        <fo:table-column column-width="56%"/>
                        <fo:table-column column-width="22%"/>
                        <fo:table-body>
                            <fo:table-row>
                                <fo:table-cell>
                                    <fo:block text-align="left">
                                        <!-- 二维码图片所在位置 -->
                                        <fo:external-graphic src="image/qrcode.png" content-width="60pt" content-height="60pt"/>
                                    </fo:block>
                                </fo:table-cell>
                                <fo:table-cell display-align="center">
                                    <fo:block text-align="center" font-family="SimSun" font-size="20pt">
                                        电子发票(增值税专用发票)
                                    </fo:block>
                                    <fo:block text-align="center" font-family="SimSun" font-size="14pt">
                                        ==========================
                                    </fo:block>
                                    <fo:block text-align="center" space-before="-50pt"> <!-- 使用负值移动位置 -->
                                        <!-- 章图片所在位置 -->
                                        <fo:external-graphic src="image/seal.png" content-width="70pt" content-height="70pt"/>
                                    </fo:block>
                                </fo:table-cell>
                                <fo:table-cell font-size="10pt" display-align="center" text-align="left">
                                    <fo:block>发票号码:123456789</fo:block>
                                    <fo:block>开票日期:2024年01月01日</fo:block>
                                </fo:table-cell>
                            </fo:table-row>
                        </fo:table-body>
                    </fo:table>
                </fo:block>

                <!-- Buyer and Seller Information -->
                <fo:block font-family="SimSun" font-size="10pt">
                    <fo:table table-layout="fixed" width="100%" border-style="solid" border-width="0.5pt">
                        <fo:table-column column-width="5%" border-style="solid" border-color="rgb(188, 119, 76)" />
                        <fo:table-column column-width="45%" border-style="solid" border-color="rgb(188, 119, 76)" />
                        <fo:table-column column-width="5%" border-style="solid" border-color="rgb(188, 119, 76)" />
                        <fo:table-column column-width="45%" border-style="solid" border-color="rgb(188, 119, 76)" />
                        <fo:table-body>
                            <fo:table-row>
                                <fo:table-cell padding="5pt" writing-mode="tb-rl">
                                    <fo:block>购买方信息</fo:block>
                                </fo:table-cell>
                                <fo:table-cell display-align="center">
                                    <fo:block>名称:</fo:block>
                                    <fo:block>统一社会信用代码/纳税人识别号:</fo:block>
                                </fo:table-cell>
                                <fo:table-cell padding="5pt" writing-mode="tb-rl">
                                    <fo:block>销售方信息</fo:block>
                                </fo:table-cell>
                                <fo:table-cell display-align="center">
                                    <fo:block>名称:</fo:block>
                                    <fo:block>统一社会信用代码/纳税人识别号:</fo:block>
                                </fo:table-cell>
                            </fo:table-row>
                        </fo:table-body>
                    </fo:table>
                </fo:block>

                <!-- Item Details Table -->
                <fo:block font-family="SimSun" font-size="10pt">
                    <fo:table table-layout="fixed" width="100%" border-style="solid" border-color="rgb(188, 119, 76)" border-width="0.5pt">
                        <fo:table-column column-width="20%" border-left-style="solid" border-color="rgb(188, 119, 76)"/>
                        <fo:table-column column-width="10%" border-color="rgb(188, 119, 76)"/>
                        <fo:table-column column-width="10%" border-color="rgb(188, 119, 76)"/>
                        <fo:table-column column-width="10%" border-color="rgb(188, 119, 76)"/>
                        <fo:table-column column-width="15%" border-color="rgb(188, 119, 76)"/>
                        <fo:table-column column-width="10%" border-color="rgb(188, 119, 76)"/>
                        <fo:table-column column-width="15%" border-color="rgb(188, 119, 76)"/>
                        <fo:table-column column-width="10%" border-right-style="solid" border-color="rgb(188, 119, 76)"/>
                        <fo:table-header>
                            <fo:table-row>
                                <fo:table-cell text-align="center"><fo:block>项目名称</fo:block></fo:table-cell>
                                <fo:table-cell text-align="center"><fo:block>规格型号</fo:block></fo:table-cell>
                                <fo:table-cell text-align="center"><fo:block>单位</fo:block></fo:table-cell>
                                <fo:table-cell text-align="center"><fo:block>数量</fo:block></fo:table-cell>
                                <fo:table-cell text-align="center"><fo:block>单价</fo:block></fo:table-cell>
                                <fo:table-cell text-align="center"><fo:block>金额</fo:block></fo:table-cell>
                                <fo:table-cell text-align="center"><fo:block>税率/征收率</fo:block></fo:table-cell>
                                <fo:table-cell text-align="center"><fo:block>税额</fo:block></fo:table-cell>
                            </fo:table-row>
                        </fo:table-header>
                        <fo:table-body min-height="50pt">
                            <fo:table-row>
                                <fo:table-cell text-align="center" padding-top="5pt"><fo:block>商品A</fo:block></fo:table-cell>
                                <fo:table-cell text-align="center" padding-top="5pt"><fo:block>型号A</fo:block></fo:table-cell>
                                <fo:table-cell text-align="center" padding-top="5pt"><fo:block>件</fo:block></fo:table-cell>
                                <fo:table-cell text-align="center" padding-top="5pt"><fo:block>1</fo:block></fo:table-cell>
                                <fo:table-cell text-align="center" padding-top="5pt"><fo:block>100.00</fo:block></fo:table-cell>
                                <fo:table-cell text-align="center" padding-top="5pt"><fo:block>100.00</fo:block></fo:table-cell>
                                <fo:table-cell text-align="center" padding-top="5pt"><fo:block>10%</fo:block></fo:table-cell>
                                <fo:table-cell text-align="center" padding-top="5pt"><fo:block>10.00</fo:block></fo:table-cell>
                            </fo:table-row>
                            <fo:table-row>
                                <fo:table-cell text-align="center" padding-top="5pt"><fo:block>合   计</fo:block></fo:table-cell>
                                <fo:table-cell text-align="center" padding-top="5pt"><fo:block></fo:block></fo:table-cell>
                                <fo:table-cell text-align="center" padding-top="5pt"><fo:block></fo:block></fo:table-cell>
                                <fo:table-cell text-align="center" padding-top="5pt"><fo:block></fo:block></fo:table-cell>
                                <fo:table-cell text-align="center" padding-top="5pt"><fo:block></fo:block></fo:table-cell>
                                <fo:table-cell text-align="center" padding-top="5pt"><fo:block>¥100.00</fo:block></fo:table-cell>
                                <fo:table-cell text-align="center" padding-top="5pt"><fo:block></fo:block></fo:table-cell>
                                <fo:table-cell text-align="center" padding-top="5pt"><fo:block>¥10.00</fo:block></fo:table-cell>
                            </fo:table-row>
                        </fo:table-body>
                    </fo:table>
                </fo:block>

                <!-- Summary Section -->
                <fo:block font-family="SimSun" font-size="10pt">
                    <fo:table table-layout="fixed" width="100%"  border-style="solid" border-width="0.5pt" border-color="rgb(188, 119, 76)">
                        <fo:table-column column-width="25%" border-style="solid" border-color="rgb(188, 119, 76)"/>
                        <fo:table-column column-width="40%" border-top-style="solid" border-color="rgb(188, 119, 76)"/>
                        <fo:table-column column-width="10%" border-top-style="solid" border-color="rgb(188, 119, 76)"/>
                        <fo:table-column column-width="25%" border-top-style="solid" border-right-style="solid" border-color="rgb(188, 119, 76)"/>
                        <fo:table-body>
                            <fo:table-row>
                                <fo:table-cell text-align="center" padding-top="5pt" padding-bottom="5pt">
                                    <fo:block>价税合计(大写)</fo:block>
                                </fo:table-cell>
                                <fo:table-cell text-align="left" padding-top="5pt" padding-bottom="5pt">
                                    <fo:block>壹佰壹拾元整</fo:block>
                                </fo:table-cell>
                                <fo:table-cell text-align="center" padding-top="5pt" padding-bottom="5pt">
                                    <fo:block>(小写)</fo:block>
                                </fo:table-cell>
                                <fo:table-cell text-align="left" padding-top="5pt" padding-bottom="5pt">
                                    <fo:block>¥110.00</fo:block>
                                </fo:table-cell>
                            </fo:table-row>
                        </fo:table-body>
                    </fo:table>
                </fo:block>

                <!-- Footer Section -->
                <fo:block font-family="SimSun" font-size="10pt" space-after="10pt" border-color="rgb(188, 119, 76)">
                    <fo:table table-layout="fixed" width="100%" border-style="solid" border-width="0.5pt">
                        <fo:table-column column-width="5%" border-style="solid" border-color="rgb(188, 119, 76)"/>
                        <fo:table-column column-width="95%" border-style="solid" border-color="rgb(188, 119, 76)"/>
                        <fo:table-body>
                            <fo:table-row>
                                <fo:table-cell padding="5pt" writing-mode="tb-rl">
                                    <fo:block>备注</fo:block>
                                </fo:table-cell>
                            </fo:table-row>
                        </fo:table-body>
                    </fo:table>
                    <fo:block>开票人:</fo:block>
                </fo:block>

            </fo:flow>
        </fo:page-sequence>
</fo:root>
总结

XSL-FO 提供了一个强大的格式化模型,适合用来生成电子发票等结构化文档。通过灵活的表格布局和样式控制,可以实现专业的 PDF 输出。

相关推荐
forestsea3 分钟前
【Java 解释器模式】实现高扩展性的医学专家诊断规则引擎
java·人工智能·设计模式·解释器模式
陈小于6 分钟前
springboot集成shiro和前后端分离配置
java·spring boot·后端
不修×蝙蝠19 分钟前
数据结构--数组实现栈和队列
java·数据结构·数组··队列
信息化未来25 分钟前
odoo17 档案管理之翻译2
java·服务器·前端
清山博客33 分钟前
Java将PDF保存为图片
java·开发语言·pdf
life102440 分钟前
pdf文档动态插入文字水印,45度角,旋转倾斜,位于文档中央,多行水印可插入中文
java·pdf·水印
归鸿铭41 分钟前
Html 转pdf
java·pdf·html
lix的小鱼1 小时前
Scala之Array数组
java·开发语言·后端·python·scala
计算机徐师兄1 小时前
Java基于SSM框架的校园综合服务小程序【附源码、文档】
java·微信小程序·小程序·校园综合服务小程序·java校园综合服务小程序·校园综合服务微信小程序
柔弱女子爱java1 小时前
XML文件(超详细):XML文件概念、作用、写法、如何用程序解析XML、写入XML、dom4j框架、DTD文档、schema文档
xml·java·开发语言·后端