如何使用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 输出。

相关推荐
会飞的架狗师13 分钟前
【Spring】Spring框架中有有哪些常见的设计模式
java·spring·设计模式
Jakarta EE24 分钟前
在JPA和EJB中用乐观锁解决并发问题
java
花心蝴蝶.34 分钟前
并发编程中常见的锁策略
java·jvm·windows
A_cot43 分钟前
一篇Spring Boot 笔记
java·spring boot·笔记·后端·mysql·spring·maven
tryCbest2 小时前
java8之Stream流
java·后端
江梦寻3 小时前
解决SLF4J: Class path contains multiple SLF4J bindings问题
java·开发语言·spring boot·后端·spring·intellij-idea·idea
鸡鸭扣3 小时前
springboot苍穹外卖实战:五、公共字段自动填充(aop切面实现)+新增菜品功能+oss
java·spring boot·后端
徐*红5 小时前
java 线程池
java·开发语言
尚学教辅学习资料5 小时前
基于SSM的养老院管理系统+LW示例参考
java·开发语言·java毕设·养老院
2401_857636395 小时前
计算机课程管理平台:Spring Boot与工程认证的结合
java·spring boot·后端