使用 Python-pptx,PowerPoint 在什么条件下会出现 KeyError?
Using Python-pptx, what conditions could a PowerPoint have that give KeyError?
我有一个 PowerPoint,我想将其打开、修改并另存为不同的文件名。但是,我遇到了 KeyError。
我用空白的 PowerPoint 演示文稿尝试了这段代码,它运行良好。但是,当我使用代码打开现有的 PowerPoint 演示文稿并尝试 运行 相同的代码时,我得到一个 KeyError。
按键错误:"There is no item named 'ppt/slides/NULL' in the archive"
#Replace Source Text
import re
#s = "string. With. Punctuation?"
#s = re.sub(r'[^\w\s]','',s)
search_str = '{{{FILTER}}}'
repl_str = re.sub(r'[^\w\s]','',(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 演示文稿引发错误???我计划开始制作几个 "templates" 并且真的需要知道是否有任何必须遵守的严格规则。
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-42-41deffabe2f9> in <module>()
7 search_str = '{{{FILTER}}}'
8 repl_str = re.sub(r'[^\w\s]','',(str(list(dashboard_filter2.values()))))
----> 9 ppt = Presentation('HispPres1.pptx')
10
11 for slide in ppt.slides:
~\AppData\Local\Continuum\anaconda3\lib\site-packages\pptx\api.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):
~\AppData\Local\Continuum\anaconda3\lib\site-packages\pptx\opc\package.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)
~\AppData\Local\Continuum\anaconda3\lib\site-packages\pptx\opc\pkgreader.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()
~\AppData\Local\Continuum\anaconda3\lib\site-packages\pptx\opc\pkgreader.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)
~\AppData\Local\Continuum\anaconda3\lib\site-packages\pptx\opc\pkgreader.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
~\AppData\Local\Continuum\anaconda3\lib\site-packages\pptx\opc\pkgreader.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
~\AppData\Local\Continuum\anaconda3\lib\site-packages\pptx\opc\pkgreader.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(
~\AppData\Local\Continuum\anaconda3\lib\site-packages\pptx\opc\phys_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):
~\AppData\Local\Continuum\anaconda3\lib\zipfile.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
~\AppData\Local\Continuum\anaconda3\lib\zipfile.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':
~\AppData\Local\Continuum\anaconda3\lib\zipfile.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"
是啊,这个问题有点棘手。该规范没有提供 "broken" 关系(指的是不存在的包部分),但至少有一个库(如果我没记错的话,基于 Java)没有在某些情况下正确清理关系,在这种情况下可能是幻灯片删除操作。
解释的要点是这样的:
- PPTX 文件是一个开放打包约定 (OPC) 包。 DOCX 和 XLSX 文件是 OPC 包的其他示例。
- OPC 包是多个 部分 的 Zip 存档(官方术语,也许 package-part 更准确)。每个部分本质上是一个文件,所以类似于
slide1.xml
,它们排列在 "directory structure". 中
- 一个部分可以与其他部分相关。例如,演示文稿部分 (
presentation.xml
) 与其每个幻灯片部分相关。这些关系存储在类似 presentation.xml.rels
的文件中。该关系以 "rId3"
之类的字符串作为键,并通过其在包中的路径标识相关部分。
- 一部分引用另一部分使用其XML中的键(例如
<p:sldId r:id="rId3"/>
)。目标部分是 .rels 文件中的 "looked-up" 以找到它的路径并以这种方式到达它。
- 你得到的
KeyError
意味着 .rels 文件有一个 <Relationship>
元素引用 ppt/slides/NULL
部分(而不是 ppt/slides/slide3.xml
之类的东西)。由于包中没有这部分,所以查找失败。
如果您在 PowerPoint 中打开 "template" 文件并保存,我认为它会自行修复。您可能需要重新排列幻灯片并将其移回原处以挤满那部分代码。
如果这不起作用,您将需要手动修补程序包,删除任何损坏的引用和关系。 opc-diag
可以派上用场。
所以,感谢 Scanny 的帮助。你完全正确。查找正在寻找 ppt/slides/slide#.xml 并且没有找到它的关系。原因是因为关系被编码为 slides/slide#.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:
您可以通过以下方式清除悬挂关系中的 PPTX:
文件 -> 信息 -> 检查问题 -> 检查文档。
清理、保存、重播 python 脚本。
我有一个 PowerPoint,我想将其打开、修改并另存为不同的文件名。但是,我遇到了 KeyError。
我用空白的 PowerPoint 演示文稿尝试了这段代码,它运行良好。但是,当我使用代码打开现有的 PowerPoint 演示文稿并尝试 运行 相同的代码时,我得到一个 KeyError。
按键错误:"There is no item named 'ppt/slides/NULL' in the archive"
#Replace Source Text
import re
#s = "string. With. Punctuation?"
#s = re.sub(r'[^\w\s]','',s)
search_str = '{{{FILTER}}}'
repl_str = re.sub(r'[^\w\s]','',(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 演示文稿引发错误???我计划开始制作几个 "templates" 并且真的需要知道是否有任何必须遵守的严格规则。
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-42-41deffabe2f9> in <module>()
7 search_str = '{{{FILTER}}}'
8 repl_str = re.sub(r'[^\w\s]','',(str(list(dashboard_filter2.values()))))
----> 9 ppt = Presentation('HispPres1.pptx')
10
11 for slide in ppt.slides:
~\AppData\Local\Continuum\anaconda3\lib\site-packages\pptx\api.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):
~\AppData\Local\Continuum\anaconda3\lib\site-packages\pptx\opc\package.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)
~\AppData\Local\Continuum\anaconda3\lib\site-packages\pptx\opc\pkgreader.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()
~\AppData\Local\Continuum\anaconda3\lib\site-packages\pptx\opc\pkgreader.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)
~\AppData\Local\Continuum\anaconda3\lib\site-packages\pptx\opc\pkgreader.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
~\AppData\Local\Continuum\anaconda3\lib\site-packages\pptx\opc\pkgreader.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
~\AppData\Local\Continuum\anaconda3\lib\site-packages\pptx\opc\pkgreader.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(
~\AppData\Local\Continuum\anaconda3\lib\site-packages\pptx\opc\phys_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):
~\AppData\Local\Continuum\anaconda3\lib\zipfile.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
~\AppData\Local\Continuum\anaconda3\lib\zipfile.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':
~\AppData\Local\Continuum\anaconda3\lib\zipfile.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"
是啊,这个问题有点棘手。该规范没有提供 "broken" 关系(指的是不存在的包部分),但至少有一个库(如果我没记错的话,基于 Java)没有在某些情况下正确清理关系,在这种情况下可能是幻灯片删除操作。
解释的要点是这样的:
- PPTX 文件是一个开放打包约定 (OPC) 包。 DOCX 和 XLSX 文件是 OPC 包的其他示例。
- OPC 包是多个 部分 的 Zip 存档(官方术语,也许 package-part 更准确)。每个部分本质上是一个文件,所以类似于
slide1.xml
,它们排列在 "directory structure". 中
- 一个部分可以与其他部分相关。例如,演示文稿部分 (
presentation.xml
) 与其每个幻灯片部分相关。这些关系存储在类似presentation.xml.rels
的文件中。该关系以"rId3"
之类的字符串作为键,并通过其在包中的路径标识相关部分。 - 一部分引用另一部分使用其XML中的键(例如
<p:sldId r:id="rId3"/>
)。目标部分是 .rels 文件中的 "looked-up" 以找到它的路径并以这种方式到达它。 - 你得到的
KeyError
意味着 .rels 文件有一个<Relationship>
元素引用ppt/slides/NULL
部分(而不是ppt/slides/slide3.xml
之类的东西)。由于包中没有这部分,所以查找失败。
如果您在 PowerPoint 中打开 "template" 文件并保存,我认为它会自行修复。您可能需要重新排列幻灯片并将其移回原处以挤满那部分代码。
如果这不起作用,您将需要手动修补程序包,删除任何损坏的引用和关系。 opc-diag
可以派上用场。
所以,感谢 Scanny 的帮助。你完全正确。查找正在寻找 ppt/slides/slide#.xml 并且没有找到它的关系。原因是因为关系被编码为 slides/slide#.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:
您可以通过以下方式清除悬挂关系中的 PPTX:
文件 -> 信息 -> 检查问题 -> 检查文档。
清理、保存、重播 python 脚本。