При использовании Python-pptx, какие условия могут быть в PowerPoint, которые дают KeyError? - PullRequest
0 голосов
/ 08 апреля 2019

У меня есть 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')

Я ожидаю внесения поправок в существующую PowerPoint, найдя все экземпляры {{{FILTER}}} и заменив его указанным значением.Тем не менее, похоже, что есть проблема с использованием моей существующей презентации 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"

Ответы [ 2 ]

0 голосов
/ 09 апреля 2019

Итак, спасибо 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".При просмотре PresentationML с использованием opc-diag я обнаружил, что связь была настроена так: <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:

0 голосов
/ 08 апреля 2019

Да, это немного сложная проблема. Спецификация не предусматривает «нарушенные» отношения (те, которые относятся к части пакета, которая не существует), но по крайней мере одна библиотека (на основе 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 может пригодиться для этого.

...