如何使用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业务场景,通过深入剖析数据治理难题,提供了新思路和实战经验,…...

Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...

基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...