python使用docxtpl处理word文档图片不显示问题
安装docxtpl:
pip install docxtpl
基本使用实例main.py:
from docxtpl import DocxTemplate
doc = DocxTemplate("my_word_template.docx")
sd = doc.new_subdoc("my_subdoc.docx")
context = {
'company_name': "World company",
'sub_doc': sd,
}
doc.render(context)
doc.save("generated_doc.docx")
其中模板文件my_word_template.docx内容如下:
子文件my_subdoc.docx内容如下:
执行main.py生成generated_doc.docx文件
import docx
from docxtpl import DocxTemplate, Subdoc
import os
from win32com import client as wc
from xml.etree.ElementTree import ElementTree,Element
import shutil
Namespaces = {
'w': 'http://schemas.microsoft.com/office/word/2003/wordml',
'wx':'http://schemas.microsoft.com/office/word/2003/auxHint',
'aml':'http://schemas.microsoft.com/aml/2001/core',
'wpc':'http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas',
'cx':'http://schemas.microsoft.com/office/drawing/2014/chartex',
'cx1':'http://schemas.microsoft.com/office/drawing/2015/9/8/chartex',
'cx2':'http://schemas.microsoft.com/office/drawing/2015/10/21/chartex',
'cx3':'http://schemas.microsoft.com/office/drawing/2016/5/9/chartex',
'cx4':'http://schemas.microsoft.com/office/drawing/2016/5/10/chartex',
'cx5':'http://schemas.microsoft.com/office/drawing/2016/5/11/chartex',
'cx6':'http://schemas.microsoft.com/office/drawing/2016/5/12/chartex',
'cx7':'http://schemas.microsoft.com/office/drawing/2016/5/13/chartex',
'cx8':'http://schemas.microsoft.com/office/drawing/2016/5/14/chartex',
'dt':'uuid:C2F41010-65B3-11d1-A29F-00AA00C14882',
'mc':'http://schemas.openxmlformats.org/markup-compatibility/2006',
'aink':'http://schemas.microsoft.com/office/drawing/2016/ink',
'am3d':'http://schemas.microsoft.com/office/drawing/2017/model3d',
'o':'urn:schemas-microsoft-com:office:office',
'v':'urn:schemas-microsoft-com:vml',
'w10':'urn:schemas-microsoft-com:office:word',
'wne':'http://schemas.microsoft.com/office/word/2006/wordml',
'wsp':'http://schemas.microsoft.com/office/word/2003/wordml/sp2',
'sl':'http://schemas.microsoft.com/schemaLibrary/2003/core',
}
class LilyDocTpl(object):
def __init__(self,MasterDocpath,SubDocpath,Outpath):
self.MasterDocpath=MasterDocpath
self.SubDocpath=SubDocpath
self.Outpath=Outpath
OutAbspath=os.getcwd()
if os.path.exists('./temp')==False:
os.mkdir(OutAbspath + './temp')
self.temppath=os.path.join(OutAbspath,'temp')
self.tempdocx=os.path.join(self.temppath,'tempdocx.docx')
def MakeTemDocx(self,**argv):
context={
}
doc=DocxTemplate(self.MasterDocpath)
for key in argv:
if argv[key][1]==1:
sd=doc.new_subdoc(argv[key][0])
context[key]=sd
elif argv[key][1]==0:
context[key]=argv[key][0]
doc.render(context)
doc.save(self.tempdocx)
def MakeTemXml(self,filepath):
word = wc.Dispatch('Word.Application')
doc = word.Documents.Open(filepath)
filename=os.path.split(filepath)[-1][:-5]+'.xml'
temxml=os.path.join(self.temppath,filename)
doc.SaveAs(temxml,11)
doc.Close()
word.Quit()
return temxml
def read_xml(self,in_path):
tree = ElementTree()
tree.parse(in_path)
return tree
def find_nodes(self,tree, path,Namespaces):
return tree.findall(path,Namespaces)
def write_xml(self,tree, out_path):
tree.write(out_path, encoding="utf-8",xml_declaration=True)
def GetPWithPic(self,Subpath):
Parr={
}
root=self.read_xml(Subpath).getroot()
BodyTag=self.find_nodes(root,"w:body",Namespaces)
SectTag=self.find_nodes(BodyTag[0],"wx:sect",Namespaces)
for item in SectTag[0].getchildren():
wr=self.find_nodes(item, "w:r",Namespaces)
if wr:
if self.find_nodes(wr[0], "w:pict",Namespaces):
rsidR=item.attrib["{http://schemas.microsoft.com/office/word/2003/wordml/sp2}rsidR"]
Parr[rsidR]=item
return Parr
# 查找生成docx文件中含图片的标签p并根据rsidR替换
def ChangePic(self,examplepath,Subpath):
Parr=self.GetPWithPic(Subpath)
tree=self.read_xml(examplepath)
indexarr={
}
root=tree.getroot()
BodyTag = self.find_nodes(root, "w:body",Namespaces)
SectTag=self.find_nodes(BodyTag[0], "wx:sect",Namespaces)
# SectionTag=find_nodes(SectTag[0], "wx:sub-section",Namespaces)
PTag=self.find_nodes(SectTag[0], "w:p",Namespaces)
for index,item in enumerate(SectTag[0].getchildren()):
wr=self.find_nodes(item, "w:r",Namespaces)
if wr:
for item2 in wr:
if self.find_nodes(item2, "w:pict",Namespaces):
rsidR=item.attrib["{http://schemas.microsoft.com/office/word/2003/wordml/sp2}rsidR"]
SectTag[0].insert(index,Parr[rsidR])
SectTag[0].remove(SectTag[0].getchildren()[index+1])
indexarr[index]=rsidR
self.filename=os.path.split(examplepath)[-1][:-5]+'.xml'
self.write_xml(tree, os.path.join(self.temppath,self.filename))
def XmltoDocx(self):
word = wc.Dispatch('Word.Application')
doc = word.Documents.Open(os.path.join(self.temppath,self.filename))
doc.SaveAs(self.Outpath, 16)
doc.Close()
word.Quit()
def DelTemp(self):
filelist=[]
rootdir=self.temppath
filelist=os.listdir(rootdir)
for f in filelist:
filepath = os.path.join( rootdir, f )
if os.path.isfile(filepath):
os.remove(filepath)
elif os.path.isdir(filepath):
shutil.rmtree(filepath,True)
shutil.rmtree(rootdir,True)
def GetTplDocx(self,**context):
self.MakeTemDocx(**context)
examplepath=self.MakeTemXml(self.tempdocx)
Subpath=self.MakeTemXml(self.SubDocpath)
self.ChangePic(examplepath,Subpath)
self.XmltoDocx()
self.DelTemp()
def main():
MasterDocpath="../my_word_template.docx"
SubDocpath="../my_subdoc.docx"
Outpath="../generated_doc.docx"
demo=LilyDocTpl(MasterDocpath,SubDocpath,Outpath)
context={
"company_name":["World company",0],"sub_doc":[demo.SubDocpath,1]}
demo.GetTplDocx(**context)
if __name__ == '__main__':
main()