如何在Python中基于模板生成ODT文件?
实现Python填充ODT模板的可行方案
1. 使用odfpy(当前维护的ODF处理库)
odfpy是目前仍在持续维护的Open Document格式操作库,支持读取模板、替换占位符/锚点。具体步骤:
- 提前在ODT模板中设置占位符,比如
{{username}}、{{order_id}}这类标识 - 用
odfpy加载模板文档,遍历文本元素替换占位符为数据库数据 - 保存为新的ODT文件
示例代码:
from odf.opendocument import load from odf.text import P from odf.table import TableCell def fill_odt_template(template_path, output_path, data): doc = load(template_path) # 替换普通段落中的占位符 for para in doc.getElementsByType(P): text = para.getAttribute('text') or '' for key, val in data.items(): placeholder = f'{{{{{key}}}}}' if placeholder in text: para.setAttribute('text', text.replace(placeholder, str(val))) # 替换表格单元格中的占位符(如果模板有表格) for cell in doc.getElementsByType(TableCell): for para in cell.getElementsByType(P): text = para.getAttribute('text') or '' for key, val in data.items(): placeholder = f'{{{{{key}}}}}' if placeholder in text: para.setAttribute('text', text.replace(placeholder, str(val))) doc.save(output_path) # 调用示例(data为数据库查询结果) db_data = {'username': '王大锤', 'order_id': 'OD20240501001', 'total': 299.9} fill_odt_template('order_template.odt', 'filled_order.odt', db_data)
2. 结合Jinja2模板引擎操作ODT的XML结构
ODT本质是压缩包+XML文件的组合,用Jinja2渲染核心XML文件的方式,能应对复杂模板(比如循环生成表格行、条件显示内容),并非“不规范”——这是利用ODF开放格式特性的常规操作:
- 把ODT模板解压到临时目录,取出
content.xml(存储文档核心内容) - 在
content.xml中添加Jinja2语法的占位符、循环或条件语句 - 用Python渲染XML后重新打包成ODT
示例代码:
import jinja2 import zipfile import os import shutil def render_odt_template(template_path, output_path, data): # 临时目录用于存放解压后的模板文件 temp_dir = 'odt_temp' os.makedirs(temp_dir, exist_ok=True) # 解压ODT模板 with zipfile.ZipFile(template_path, 'r') as zf: zf.extractall(temp_dir) # 用Jinja2渲染content.xml env = jinja2.Environment(loader=jinja2.FileSystemLoader(temp_dir), autoescape=False) content_template = env.get_template('content.xml') rendered_content = content_template.render(data) with open(os.path.join(temp_dir, 'content.xml'), 'w', encoding='utf-8') as f: f.write(rendered_content) # 重新打包成ODT with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as zf: for root, _, files in os.walk(temp_dir): for file in files: file_path = os.path.join(root, file) arcname = os.path.relpath(file_path, temp_dir) zf.write(file_path, arcname) # 清理临时目录 shutil.rmtree(temp_dir) # 调用示例(支持列表循环,比如订单明细) db_data = { 'username': '李小花', 'order_id': 'OD20240501002', 'items': [ {'name': '无线鼠标', 'price': 99.9, 'count': 1}, {'name': '机械键盘', 'price': 199, 'count': 1} ] } render_odt_template('order_template.odt', 'filled_order.odt', db_data)
关于“主流库偏少”的说明
ODT格式的受众确实不如DOCX广泛,导致专门的模板填充库数量不多,但上述两种方法都是稳定可行的:
odfpy足够覆盖简单到中等复杂度的模板需求,且目前仍有维护更新- Jinja2+XML的方式灵活性极强,能处理几乎所有复杂模板场景,完全符合ODF格式的设计规范
内容的提问来源于stack exchange,提问作者ibi0tux
相关产品推荐
相关产品推荐

