如何使用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 输出。
相关文章:
如何使用XSL-FO生成PDF格式的电子发票的技术博文示例
目录 使用 XSL-FO 生成电子发票 PDF:从布局设计到优化为什么选择 XSL-FO?1. 初始设置2. 标题区块3. 买卖方信息4. 商品明细表格5. 合计信息6. 优化代码结构与布局7. 生成 PDF 文件8. 示例总结 使用 XSL-FO 生成电子发票 PDF:从布局设计到优化…...
TDengine 签约山东港,赋能港口数字化转型
随着全球港口物流数字化进程的加速,港口运营面临日益复杂的数据管理挑战,从能源管理、设备监控到运营安全保障,各类数据需要及时存储并高效分析。山东港在信息化建设过程中,数字化综合管理平台的性能和查询功能一度受到瓶颈制约。…...
基于YOLO11/v10/v8/v5深度学习的煤矿传送带异物检测系统设计与实现【python源码+Pyqt5界面+数据集+训练代码】
《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…...
mysql-workbench 导入csv格式数据报错:Unhandled exception: Could not determine delimiter
xlsx文件中第二行某个单元格有换行符,csv文件中用双引号包起来了,但是python 在采样的时候,只读了前两行,readline可不认识csv的规则。csv文件可以识别双引号包起来的换行符是单元格内部的换行,python的readline识别不…...
使用Python简单实现客户端界面
服务端实现 import threading import timeimport wx from socket import socket, AF_INET, SOCK_STREAMclass LServer(wx.Frame):def __init__(self):wx.Frame.__init__(self, None, id1002, titleL服务器端界面, poswx.DefaultPosition, size(400, 450))# 窗口中添加面板pl …...
15分钟学 Go 第 43 天:前端与Go的结合
第43天:前端与Go的结合 目标:了解Go如何与前端交互,前端使用Vue.js 在现代Web开发中,Go语言常用于后端开发,而Vue.js是一个流行的前端框架,用于构建用户界面。结合二者,可以构建高效、可维护的…...
解决SRS推送webrtc流卡顿问题
目录 1.问题描述2.原因分析3.ffmpeg去掉B帧的方法3.1 命令行推流3.2 ffmpeg源码推流 1.问题描述 使用ffmpeg通过rtmp协议推流给SRS,然后浏览器通过webrtc拉取播放流,经多次测试发现webrtc播放流总是卡顿,而拉取rtmp流是正常的。 2.原因分析…...
GDPU Andriod移动应用 Broadcast Receiver
聆听广播,跟着节拍吧。 计时器 新建一个名为PhoneStateMonitor的工程; 实现一个应用运行时长的计时器,并在界面上刷新计数器,要求包括: (1)在Layout中包含两个TextView控件,横向分…...
CSP/信奥赛C++刷题训练:经典例题 - 栈(1):洛谷P3056 :[USACO12NOV] Clumsy Cows S
CSP/信奥赛C刷题训练:经典例题 - 栈(1):洛谷P3056 :[USACO12NOV] Clumsy Cows S 题目描述 Bessie the cow is trying to type a balanced string of parentheses into her new laptop, but she is sufficiently clums…...
WiFi一直获取不到IP地址是怎么回事?
在当今这个信息化时代,WiFi已成为我们日常生活中不可或缺的一部分。无论是家庭、办公室还是公共场所,WiFi都为我们提供了便捷的无线互联网接入。然而,有时我们可能会遇到WiFi连接后无法获取IP地址的问题,这不仅影响了我们的网络使…...
蓝牙BLE开发——iOS 每次写入数据超过200字节报错?
iOS 写入数据超过200字节报错 文章目录 iOS 写入数据超过200字节报错官方建议:报错问题解决 writeblecharacteristicvalue 官方建议: 并行调用多次会存在写失败的可能性。APP不会对写入数据包大小做限制,但系统与蓝牙设备会限制蓝牙4.0单次…...
Ascend Extension for PyTorch是个what?
1 Ascend Extension for PyTorch Ascend Extension for PyTorch 插件是基于昇腾的深度学习适配框架,使昇腾NPU可以支持PyTorch框架,为PyTorch框架的使用者提供昇腾AI处理器的超强算力。 项目源码地址请参见Ascend/Pytorch。 昇腾为基于昇腾处理器和软…...
学习docker第五弹-----高级篇start-Dockerfile
docker目录 1 Dockerfile是什么2 Dockerfile能干嘛3 如何书写Dockerfile3.1 Dockerfile构建过程解析3.2 小总结3.3 Dockerfile的基本知识3.5 保留字FROMMAINTAINERRUN 有两种方式EXPOSEWORKDIRENVUSERVOLUMEADDCMDENTRYPOINT 4 后记 1 Dockerfile是什么 Dockerfile顾名思义就是…...
【Elasticsearch】Elasticsearch集成Spring Boot
Elasticsearch集成Spring Boot 概述 Spring Data Elasticsearch 介绍一、环境初始化二、实战入门1、定义数据实体类2、定义Dao层3、框架集成-SpringData-集成测试-索引操作4、框架集成-SpringData-集成测试-文档操作5、框架集成-SpringData-集成测试-文档搜索 概述 Spring Data…...
HarmonyOS 移
什么是HarmonyOS HarmonyOS 中文名字是 鸿蒙操作系统 中国神话传说盘古在昆仑山开天辟地之前,世界是一团混沌状的元气,这种自然的元气叫做鸿蒙,那个时代成为鸿蒙时代华为公司的操作系统以鸿蒙取名,是不是有开天辟地之寓意&#x…...
跨子网的WinCC客户机/服务器如何实现通讯?
为了更有效地利用有限的IP地址,为了减少广播对网络带宽的占用从而提高带宽,为了实现在不同子网中应用不同的安全策略从而提高网络安全性,现场通常要求划分子网,将安全等级要求不同的计算机安置在不同的子网中,分开管理…...
java 面向对象高级
1.final关键字 class Demo{public static void main(String[] args) {final int[] anew int[]{1,2,3};// anew int[]{4,5,6}; 报错a[0]5;//可以,解释了final修饰引用性变量,变量存储的地址不能被改变,但地址所指向的对象的内容可以改变} }什…...
递推经典例题 - 爬楼梯
一、题目阅读 题目描述 一段楼梯有n级台阶。你每次可以跨一个、两个或者三个台阶。 请问走上n级台阶有几种方案?答案对998244353取模。 输入格式 一行一个数n。 输出格式 一行一个数,表示方案数。 样例 Input 1 3 Output 1 4 样例解释 1 1 1 3 1 2 …...
OpenCV视觉分析之目标跟踪(12)找到局部的最大值函数meanShift()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在反向投影图像上找到一个对象。 meanShift 是一种用于图像处理和计算机视觉领域的算法,特别适用于目标跟踪、图像分割等任务。该算…...
《数据治理精选案例集2.0(2024版)》592页PDF(已授权分享)
《亿信华辰数据治理精选案例集2.0》是北京亿信华辰软件有限责任公司倾力打造的专业数据治理案例集,汇集了100个一线政企数据治理实践案例,覆盖13大行业和500业务场景,通过深入剖析数据治理难题,提供了新思路和实战经验,…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
