Используя Python-pptx, какие условия могут быть в PowerPoint, которые дают KeyError?

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

Не могли бы вы включить полную трассировку стека, полученную для KeyError?

quiet_laika 08.04.2019 19:36

Конечно. Извини за это. Я только что обновил вопрос, чтобы включить полный KeyError.

SoSincere3 08.04.2019 19:46

Трудно сказать без полной трассировки стека, но по какой-то причине он думает, что вы пытаетесь найти слайд с именем NULL, что кажется неправильным. Полная трассировка стека будет включать более длинную ошибку, показывающую, где в коде возникла ошибка. stackoverflow.com/help/mcve

quiet_laika 08.04.2019 19:49

Ох, хорошо. Это дает мне полную трассировку стека? import traceback traceback.print_stack()

SoSincere3 08.04.2019 20:06

Я ожидаю, что он напечатает длинную трассировку стека, когда ваша программа выйдет из строя, что-то вроде одного из этих: google.com/search?q=python+traceback&tbm=isch. Где вы запускаете этот код?

quiet_laika 08.04.2019 20:17

Извинения. Я не знал, как это называется. Я отредактировал вопрос. Спасибо за помощь.

SoSincere3 08.04.2019 20:27
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
6
1 653
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

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

Кажется, что все элементы отношений следуют этому шаблону <Relationship Id = "x" Type = "http://schemas.openxmlformats.org/officeDocument/2006/‌​relationships/slide" Target = "slides/slide1.xml"/>\n. Я не вижу пропущенных имен. Есть ли проблема с этим примером элемента?

SoSincere3 08.04.2019 23:47

Итак, спасибо 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:

Хм, ну, я рад, что у вас все заработало, но я не думаю, что ваш анализ того, почему это правильно. ссылка Target = "slides/slide1.xml" представляет собой путь родственник, и я ожидаю, что часть .rels, в которой она появляется, уже находится в «каталоге» /ppt/. Кроме того, ваше изменение кода ничего не меняет; и slides, и ppt.slides относятся к объекту Slides для представления (эта структура вызовов не связана с фактическим расположением в пакете). В любом случае, рад, что это начало работать, я просто не думаю по тем причинам, о которых вы думали :)

scanny 13.04.2019 23:12

Ты прав на 100%. По какой-то причине это работало изначально, но я не мог повторить это. У меня был шаблон компании за тем, который не работал. Когда я удаляю шаблон компании (схема шаблона мастер-слайда), он работает. Это работает, когда я просто использую базовый шаблон PowerPoint по умолчанию.

SoSincere3 15.04.2019 17:48

Очистить PPTX от оборванных отношений можно через:

Файл -> Информация -> Проверить наличие проблем -> Проверить документ.

Очистите, сохраните, воспроизведите скрипт Python.

Другие вопросы по теме