使用Python-pptx,PowerPoint有什么条件可以产生KeyError?

问题描述 投票:0回答:2

我有一个PowerPoint,我想打开,修改,并保存为不同的文件名。但是,我得到了一个KeyError。

我用一个空白的PowerPoint演示文稿尝试了这段代码,它完美无缺。但是,当我使用代码打开现有的PowerPoint演示文稿并尝试运行相同的代码时,我得到一个KeyError。

KeyError:“存档中没有名为'ppt / slides / NULL'的项目”

#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演示文稿引发错误???我计划开始制作几个“模板”,并且确实需要知道是否有任何坚固的规则要遵守。

---------------------------------------------------------------------------
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"
python-3.x python-pptx
2个回答
0
投票

是的,这是一个棘手的问题。某些规范没有提供“破坏”的关系(指的是一个不存在的包部分),但至少有一个库(如果我没记错的话,基于Java)不会在某些情况下正确清理关系在这种情况下,可能是幻灯片删除操作。

解释的要点是这样的:

  • PPTX文件是Open Packaging Convention(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可以很方便。


0
投票

所以,感谢Scanny的帮助。你是完全正确的。查找正在查找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:

© www.soinside.com 2019 - 2024. All rights reserved.