zhangyu836 / xltpl

A python module to generate xls/x files from a xls/x template.
MIT License
71 stars 17 forks source link

带有打印区域的文件在生成后用MS Office打开提示文件错误 #25

Open JIMhackKING opened 4 months ago

JIMhackKING commented 4 months ago

现象

文件有工作簿A1,A1设置一个打印区域,从A1单元格到G13单元格。使用xlsxtpl.writerx.render_book2渲染并保存后用Microsoft Office打开该文件,会提示文件错误,如下图:

image image

文件

原始文件 渲染后的文件

代码

from openpyxl import load_workbook
from xlsxtpl.writerx import BookWriter

writer = BookWriter("hello.xlsx")
wb = load_workbook("hello.xlsx", rich_text=True)

sheet_list = wb.sheetnames
payloads = [{'tpl_name': sheet, 'sheet_name': sheet, 'ctx': {}} for sheet in sheet_list]

writer.render_book2(payloads=payloads)
writer.save('test3.xlsx')

分析

从错误信息来看可知存在问题的文件是/xl/workbook.xml,将文件后缀改成.zip,然后打开/xl/workbook.xml文件。 原始文件的内容:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<workbook  xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x15" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main">
    <fileVersion  appName="xl" lastEdited="6" lowestEdited="5" rupBuild="14420"/>
    <workbookPr  filterPrivacy="1" defaultThemeVersion="124226"/>
    <bookViews>
        <workbookView  xWindow="240" yWindow="120" windowWidth="16155" windowHeight="8505"/>
    </bookViews>
    <sheets>
        <sheet  name="A1" sheetId="1" r:id="rId1"/>
    </sheets>
    <definedNames>
        <definedName  name="_xlnm.Print_Area" localSheetId="0">'A1'!$A$1:$G$13</definedName>
    </definedNames>
    <calcPr  calcId="145621"/>
</workbook>

这里需要重点关注这一段:

<definedNames>
    <definedName  name="_xlnm.Print_Area" localSheetId="0">'A1'!$A$1:$G$13</definedName>
</definedNames>

这里打印区域的值是:'A1'!$A$1:$G$13

然后查看渲染后生成的文件的 xml 设置:

<definedNames>
    <definedName  name="_xlnm.Print_Area" localSheetId="0">A1:G13</definedName>
</definedNames>

这里打印区域的值是:A1:G13

两个值不一样,转换后的文件打印区域的值不完整

临行处理方案

需要将所有工作簿的打印区域重新设置一次再保存,才能将这个值设置为正确格式,openpyxl会帮我们修正这个格式。

...

writer.render_book2(payloads=payloads)
for sheet in writer.workbook.worksheets:
    sheet.print_area = sheet.print_area
writer.save('test3.xlsx')