使用Python-pptx,PowerPoint可以具有哪些条件来提供KeyError?



我有一个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:

最新更新