当前位置: 首页 > article >正文

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

目录

      • 使用 XSL-FO 生成电子发票 PDF:从布局设计到优化
        • 为什么选择 XSL-FO?
        • 1. 初始设置
        • 2. 标题区块
        • 3. 买卖方信息
        • 4. 商品明细表格
        • 5. 合计信息
        • 6. 优化代码结构与布局
        • 7. 生成 PDF 文件
        • 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> 中设置页面布局:

<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> 元素来布局这些信息,利用列宽度来控制内容的对齐和分布:

<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> 元素创建一个两列的表格来放置这些信息:

<fo:table-column column-width="5%"/>
<fo:table-column column-width="45%"/>

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

4. 商品明细表格

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

<fo:table-column column-width="20%"/>
...

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

5. 合计信息

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

<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 文件:

fop -xml invoice.xml -xsl invoice.xsl -pdf invoice.pdf

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

8. 示例
<?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 输出。


http://www.kler.cn/a/391122.html

相关文章:

  • 前端神经网络入门(三):深度学习与机器学习的关系、区别及核心理论支撑 - 以Brain.js示例
  • python: postgreSQL using psycopg2 or psycopg
  • 以色列支付龙头遭DDoS攻击,各地超市加油站等POS机瘫痪
  • 一文详解java的数据类型
  • 基于promtail+loki+grafana搭建日志系统
  • Python网络爬虫与数据采集实战——什么是网络爬虫
  • 负梯度方法与Newton型方法-数值最优化方法-课程学习笔记-4
  • Spring Boot基础教学:Spring Boot的核心特性
  • sql表的约束练习题
  • git commit 校验
  • 数学建模---利用Matlab快速实现机器学习(上)
  • 技术人,在数字化转型中如何为企业赋能?
  • Vuex 与 Pinia:Vue 状态管理库的选择与对比
  • 基于YOLOv5的人群密度检测系统设计与实现
  • Oracle 数据库创建导入
  • 基于Multisim温度计温度测量温度超限报警电路(含仿真和报告)
  • gitlab 流水线流程简要说明
  • 用于图像识别的判别图正则化技术
  • 《云原生安全攻防》-- K8s安全防护思路
  • Go语言开发基于SQLite数据库实现用户表增删改查项目搭建(一)
  • adb 如何通过wifi连接手机
  • 吴恩达机器学习笔记(3)
  • 机器学习——特征工程、正则化、强化学习
  • 软件测试项目实战
  • Playwright 自动化测试与爬虫快速入门指南
  • 华为云软件开发生产线(CodeArts)10月新功能特性