gpt4 book ai didi

用于 VBA 加载项文件的 Python 构建脚本

转载 作者:太空宇宙 更新时间:2023-11-03 11:49:28 27 4
gpt4 key购买 nike

我已经编写了一个 python 脚本,它将作为我支持的启用宏的 PowerPoint 文件的“构建脚本”。

该脚本创建一个新的空 PowerPoint 演示文稿,导入所有 VBA 模块,保存文件并将其转换为 ZIP 存档,以便插入 RibbonUI 配置 (ribbon_xml.xml文件和 mylogo.jpg 文件)。

所有这些都或多或少地按预期工作——直到我尝试使用输出文件(手动将 .zip 重命名为 .pptm 并在 PowerPoint 中打开它)。

错误代码完全退出,但输出存档 (copy.zip) 在转换为 PPTM 文件时无法正常打开。

我收到配置有问题的警告,PowerPoint 将尝试修复该文件。

PowerPoint,就其本质而言,当然并没有指出问题所在,只是它发现了“不可读的内容”并且此类内容已“被删除”......我在比较一些文件后唯一能看到的我手动创建的是 CustomUI 的 XML 属性似乎使用某种 GUID 作为其 id 属性的一部分

当前的解决方法:函数 build_ribbon 可以使用 CustomUI Editor 工具手动完成,大约需要 3 分钟才能可靠地生成 PPTM 输出。

所以这不是一个特别的“Python”问题,因为它是一个关于 CustomUI XML/ribbon XML 接口(interface)的实现的问题。

完整代码:

import win32com.client
import os
import zipfile
import uuid

#### PARAMETERS
vba_source_control_path = r"C:\Repos\MyAddIn\VBA\ChartBuilder_PPT\Modules"
output_path = r"C:\debug\output.pptm"
ribbon_xml_path = r"C:\Repos\MyAddIn\Ribbon XML\ribbon_xml.xml"
ribbon_logo_path = r"C:\Repos\MyAddIn\Ribbon XML\mylogo.jpg"

def build_addin(pres, path):
"""
This procedure does the following:
1. adds all of the VBComponents to the working PPTM file

The .PPTM file is used for local development & debugging and
is only usually packaged as a PPAM for Testing and Distribution
"""

for fn in [fn for fn in os.listdir(path) if not(fn.endswith(".frx"))]:
pres.VBProject.VBComponents.Import(path + "\\" + fn)

# Clean up old files, if any
if os.path.isfile(output_path):
os.remove(output_path)
if os.path.isfile(output_path.replace(".pptm", ".zip")):
os.remove(output_path.replace(".pptm", ".zip"))

# Save the new file with VBProject components
pres.SaveAs(output_path)

pres.Close()

def build_ribbon_zip():

"""
build_ribbon_zip handles manipulation of the .ZIP contents and places the
necessary components within the PPTM ZIP archive structure
2. converts the PPTM to a .ZIP
3. Adds the CustomUI XML and logo.jpg to the .ZIP directory
4. converts the .ZIP to a PPTM
"""

id = '<Relationship Id='
schema = 'http://schemas.openxmlformats.org/officeDocument/2006/'
_path = output_path.replace(".pptm", ".zip")
copy_path = r"C:\debug\copy.zip"

# Convert to ZIP archive
os.rename(output_path, _path)
zip = zipfile.ZipFile(_path, 'a')
copy = zipfile.ZipFile(copy_path, 'w')

guid = str(uuid.uuid4()).replace('-', '')[:16]

for itm in [itm for itm in zip.infolist() if itm.filename != r'_rels/.rels']:
buffer = zip.read(itm.filename)
copy.writestr(itm, buffer)

# Append the Logo file to the .zip and create the archive
copy.write(ribbon_logo_path, r'\CustomUI\images\jdplogo.jpg')

# append the CustomUI xml part to the .zip and create the archive
copy.write(ribbon_xml_path, r'\CustomUI\customUI14.xml')

# append the .rels file to CustomUI\_rels
rels_xml = r'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
rels_xml += r'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
rels_xml += r'<Relationship Id="jdplogo" Type="'+schema+'relationships/image" Target="images/jdplogo.jpg"/>'
rels_xml += r'</Relationships>'

copy.writestr(r'CustomUI\_rels\customUI14.xml.rels', rels_xml.encode('utf-8'))

# get the existing _rels/.rels XML content and append the UI:
rels_xml = zip.read(r'_rels/.rels').rstrip()[:-16]
rels_xml += id + r'"R'+guid+'" Type="http://schemas.microsoft.com/office/2007/relationships/ui/extensibility"'
rels_xml += r'Target="customUI/customUI14.xml"/></Relationships>'

rels_xml = rels_xml.replace(os.linesep, '')
# this file-like object is read-only, and the writestr method will create another .rels file...

copy.writestr(r'_rels/.rels', rels_xml.encode('utf-8'))

zip.close()
copy.close()

if __name__ == "__main__":
"""
Procedure to create a new PowerPoint Presentation and insert the Code Modules from source control
"""
ppApp = win32com.client.Dispatch("PowerPoint.Application")

pres = ppApp.Presentations.Add(False)

pres.Slides.AddSlide(1, pres.SlideMaster.CustomLayouts(1))

build_addin(pres, vba_source_control_path)

ppApp.Quit()

build_ribbon_zip()

最佳答案

输出中缺少一些引用,导致 PowerPoint 异常。像这样解决这个问题:

def build_addin(pres, path):
"""
This procedure does the following:
1. adds all of the VBComponents to the working PPTM file
2. adds required project references
The .PPTM file is used for local development & debugging and
is only usually packaged as a PPAM for Testing and Distribution
"""

version = str(int(float(pres.Application.version)))

# import the VB Components
for fn in [fn for fn in os.listdir(path) if not(fn.endswith(".frx"))]:
pres.VBProject.VBComponents.Import(path + "\\" + fn)

# add the required project references
pres.VBProject.References.AddFromFile(r'C:\Program Files (x86)\Microsoft Office\Office'+version+'\EXCEL.EXE')
# MSForms TreeView Control
pres.VBProject.References.AddFromFile(r'C:\Windows\SysWOW64\MSCOMCTL.OCX')
# MSXML2
pres.VBProject.References.AddFromFile(r'C:\Windows\System32\msxml6.dll')
# ADODB
pres.VBProject.References.AddFromFile(r'C:\Program Files (x86)\Common Files\System\ado\msado15.dll')
# VBE Extensibility

我还在 build_ribbon 中发现了一些可能格式错误的 XML 并修复了它,但仍然不是 100%,因为 PowerPoint 在第一次打开(一次)时仍然需要“修复”文件,但之后那,它似乎按预期工作。

我注意到自定义 Logo 没有出现在功能区中,我发现“不可读的内容”可能与加载到其中一个功能区控件上的 JPG 图像文件有关。来自 this forum on OpenXMLDeveloper :

This kind of problem occurs when there is an issue in one of the following areas.

  1. Relationship Id does not match with parts
  2. Error in content_types.xml file
  3. Error in parts (document.xml or any other parts)
  4. Mismatched link between slide master-slide layout/slide layout-slide

我仔细检查了 [Content_Types].xml 文件不包含 .jpg 文件扩展名的元素。

我为 ElementTree 添加导入语句:

import xml.etree.ElementTree as ET

然后修改build_ribbon_zip如下:

def build_ribbon_zip():

"""
build_ribbon_zip handles manipulation of the .ZIP contents and places the
necessary components within the PPTM ZIP archive structure
3. converts the PPTM to a .ZIP
4. Adds the CustomUI XML to the .ZIP directory
5. converts the .ZIP to a PPTM

"""
bom = u'\ufeff'
_path=output_path.replace('.pptm', '.zip')
copy_path=r'C:\debug\copy.zip'

# Convert to ZIP archive
os.rename(output_path, _path)
z=zipfile.ZipFile(_path, 'a', zipfile.ZIP_DEFLATED)
copy=zipfile.ZipFile(copy_path, 'w', zipfile.ZIP_DEFLATED)

guid=str(uuid.uuid4()).replace('-', '')[:16]

"""
the .rels files are written directly from XML string built in procedure
the [Content_Types].xml file needs to include additional parameter for the 'jpg' extension
"""
for itm in [itm for itm in z.infolist() if itm.filename != r'_rels/.rels']:
buffer = z.read(itm.filename)
if itm.filename == "[Content_Types].xml":
# Modify the [Content_Types].xml file to include the jpg reference
# <Default Extension="jpg" ContentType="image/.jpg" />
# copy the XML from the original zip archive, this file has not been copied in the above loop
root = ET.fromstring(buffer)

ET.SubElement(root, '{http://schemas.openxmlformats.org/package/2006/content-types}Default', {'Extension': 'jpg', 'ContentType': 'image/.jpg'})

copy.writestr(itm, ET.tostring(root).encode('utf-8'))

# Append the Logo file to the .zip and create the archive
copy.write(ribbon_logo_path, r'\customUI\images\jdplogo.jpg')

else:
copy.writestr(itm, buffer)

# append the CustomUI xml part to the .zip and create the archive
copy.write(ribbon_xml_path, r'\customUI\customUI14.xml')

# create the string & append the .rels to CustomUI\_rels
rels_xml = """<?xml version="1.0" encoding="utf-8"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="images/jdplogo.jpg" Id="jdplogo" />
</Relationships>"""

copy.writestr(r'customUI\_rels\customUI14.xml.rels', rels_xml.encode('utf-8'))

# get the existing _rels/.rels XML content and copy to the copied archiveI:

rels_xml = r'<?xml version="1.0" encoding="utf-8" ?>'
rels_xml += r'<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'
rels_xml += r'<Relationship Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/'
rels_xml += r'core-properties" '
rels_xml += r'Target="docProps/core.xml" Id="rId3" />'
rels_xml += r'<Relationship Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail" '
rels_xml += r'Target="docProps/thumbnail.jpeg" Id="rId2" />'
rels_xml += r'<Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" '
rels_xml += r'Target="ppt/presentation.xml" Id="rId1" />'
rels_xml += r'<Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" '
rels_xml += r'Target="docProps/app.xml" Id="rId4" /><Relationship '
rels_xml += r'Type="http://schemas.microsoft.com/office/2007/relationships/ui/extensibility" '
rels_xml += r'Target="/customUI/customUI14.xml" Id="R'+guid+'" /></Relationships>'

copy.writestr(r'_rels\.rels', rels_xml.encode('utf-8'))

z.close()
copy.close()

os.remove(_path)
os.rename(copy_path, output_path)

关于用于 VBA 加载项文件的 Python 构建脚本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31664821/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com