我有一个PowerPoint,我想打开,修改并另存为不同的文件名。但是,我收到一个密钥错误。
我用空白的PowerPoint演示文稿尝试了这段代码,它运行良好。但是,当我使用该代码操作现有的PowerPoint演示文稿并尝试运行相同的代码时,我收到KeyError。
KeyError:"存档中没有名为'ppt/slides/NULL'的项目">
#Replace Source Text
import re
#s = "string. With. Punctuation?"
#s = re.sub(r'[^ws]','',s)
search_str = '{{{FILTER}}}'
repl_str = re.sub(r'[^ws]','',(str(list(dashboard_filter2.values()))))
ppt = Presentation('HispPres1.pptx')
for slide in ppt.slides:
for shape in slide.shapes:
if shape.has_text_frame:
shape.text = shape.text.replace(search_str, repl_str)
ppt.save('HispPresSourceUpdate.pptx')
我希望通过查找 {{{FILTER}}} 的所有实例并将其替换为列出的值来修改现有的 PowerPoint。但是,使用我现有的PowerPoint演示文稿似乎有问题。我没有空白演示文稿的问题。
所以,我想知道什么会导致现有的PowerPoint演示文稿引发错误???我计划制作几个"模板"作为开始,并且真的需要知道是否有任何硬性规则需要遵守。
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-42-41deffabe2f9> in <module>()
7 search_str = '{{{FILTER}}}'
8 repl_str = re.sub(r'[^ws]','',(str(list(dashboard_filter2.values()))))
----> 9 ppt = Presentation('HispPres1.pptx')
10
11 for slide in ppt.slides:
~AppDataLocalContinuumanaconda3libsite-packagespptxapi.py in Presentation(pptx)
28 pptx = _default_pptx_path()
29
---> 30 presentation_part = Package.open(pptx).main_document_part
31
32 if not _is_pptx_package(presentation_part):
~AppDataLocalContinuumanaconda3libsite-packagespptxopcpackage.py in open(cls, pkg_file)
120 *pkg_file*.
121 """
--> 122 pkg_reader = PackageReader.from_file(pkg_file)
123 package = cls()
124 Unmarshaller.unmarshal(pkg_reader, package, PartFactory)
~AppDataLocalContinuumanaconda3libsite-packagespptxopcpkgreader.py in from_file(pkg_file)
34 pkg_srels = PackageReader._srels_for(phys_reader, PACKAGE_URI)
35 sparts = PackageReader._load_serialized_parts(
---> 36 phys_reader, pkg_srels, content_types
37 )
38 phys_reader.close()
~AppDataLocalContinuumanaconda3libsite-packagespptxopcpkgreader.py in _load_serialized_parts(phys_reader, pkg_srels, content_types)
67 sparts = []
68 part_walker = PackageReader._walk_phys_parts(phys_reader, pkg_srels)
---> 69 for partname, blob, srels in part_walker:
70 content_type = content_types[partname]
71 spart = _SerializedPart(partname, content_type, blob, srels)
~AppDataLocalContinuumanaconda3libsite-packagespptxopcpkgreader.py in _walk_phys_parts(phys_reader, srels, visited_partnames)
102 yield (partname, blob, part_srels)
103 for partname, blob, srels in PackageReader._walk_phys_parts(
--> 104 phys_reader, part_srels, visited_partnames):
105 yield (partname, blob, srels)
106
~AppDataLocalContinuumanaconda3libsite-packagespptxopcpkgreader.py in _walk_phys_parts(phys_reader, srels, visited_partnames)
102 yield (partname, blob, part_srels)
103 for partname, blob, srels in PackageReader._walk_phys_parts(
--> 104 phys_reader, part_srels, visited_partnames):
105 yield (partname, blob, srels)
106
~AppDataLocalContinuumanaconda3libsite-packagespptxopcpkgreader.py in _walk_phys_parts(phys_reader, srels, visited_partnames)
99 visited_partnames.append(partname)
100 part_srels = PackageReader._srels_for(phys_reader, partname)
--> 101 blob = phys_reader.blob_for(partname)
102 yield (partname, blob, part_srels)
103 for partname, blob, srels in PackageReader._walk_phys_parts(
~AppDataLocalContinuumanaconda3libsite-packagespptxopcphys_pkg.py in blob_for(self, pack_uri)
107 matching member is present in zip archive.
108 """
--> 109 return self._zipf.read(pack_uri.membername)
110
111 def close(self):
~AppDataLocalContinuumanaconda3libzipfile.py in read(self, name, pwd)
1312 def read(self, name, pwd=None):
1313 """Return file bytes (as a string) for name."""
-> 1314 with self.open(name, "r", pwd) as fp:
1315 return fp.read()
1316
~AppDataLocalContinuumanaconda3libzipfile.py in open(self, name, mode, pwd, force_zip64)
1350 else:
1351 # Get info object for name
-> 1352 zinfo = self.getinfo(name)
1353
1354 if mode == 'w':
~AppDataLocalContinuumanaconda3libzipfile.py in getinfo(self, name)
1279 if info is None:
1280 raise KeyError(
-> 1281 'There is no item named %r in the archive' % name)
1282
1283 return info
KeyError: "There is no item named 'ppt/slides/NULL' in the archive"
是的,这是一个棘手的问题。该规范没有提供"断开"的关系(引用不存在的包部件),但至少有一个库(如果我没记错的话,基于 Java)在某些情况下没有正确清理关系,在这种情况下可能是幻灯片删除操作。
解释的要点是这样的:
- PPTX 文件是一个开放打包约定 (OPC) 包。DOCX和XLSX文件是OPC包的其他例子。
- OPC软件包是多个部分的Zip存档(官方术语,也许更准确地说是软件包部分)。每个部分本质上都是一个文件,所以类似于
slide1.xml
,它们排列在"目录结构"中。 - 一个部分可以与其他部分相关。例如,演示文稿部件 (
presentation.xml
) 与其每个幻灯片部件相关。这些关系存储在类似presentation.xml.rels
的文件中。该关系使用类似"rId3"
的字符串进行键控,并通过其在包中的路径标识相关部分。 - 一个部分使用其 XML 中的键引用另一个部分(例如
<p:sldId r:id="rId3"/>
)。在 .rels 文件中"查找"目标部分以查找其路径并以这种方式到达它。 - 您得到的
KeyError
意味着 .rels 文件有一个<Relationship>
元素,指的是部分ppt/slides/NULL
(而不是类似ppt/slides/slide3.xml
)。由于包中没有此类部件,因此查找失败。
如果您在PowerPoint中打开"模板"文件并保存它,我认为它会自行修复。您可能需要重新排列幻灯片并将其移回以挤挤代码的该部分。
如果这不起作用,则需要手动修补包,删除任何损坏的引用和关系。opc-diag
可以很方便。
您可以通过以下方式从悬空关系中清除 PPTX:
文件 -> 信息 -> 检查问题 ->检查文档。
清理,保存,重播python脚本。
所以,感谢斯坎尼的帮助。你说得对。查找正在寻找 ppt/slides/slide#.xml 但没有找到它的关系。原因是因为这些关系被编码为幻灯片/幻灯片#.xml(没有 ppt/)。我确实进入了opc-diag,看看我能在那里做什么,但我找到了一个简单的解决方案。
我以前的代码有一行说for slide in ppt.slides:
,这是错误:KeyError: "There is no item named 'ppt/slides/NULL' in the archive"
.当使用 opc-diag 浏览 PresentationML 时,我发现关系是这样设置的:<Relationship Id="x" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" Target="slides/slide1.xml"/>n
.该关系不包括ppt
。
因此,为了摆脱该查找并使其与PowerPoint存储幻灯片关系的方式相匹配,我更改了以下行:
ppt = Presentation('HispPres1.pptx')
for slide in ppt.slides:
对此
ppt = Presentation('HispPres1.pptx')
slides = ppt.slides
for slide in slides: