Python-pptx Добавление пользовательских свойств в файл pptx

Я пытаюсь добавить пользовательские свойства в файл pptx, используя библиотеку python-pptx. Мне удалось добавить, но не удалось сохранить файл.

Использование блоков данных Python 3.10.12. Среда выполнения: 13.3 LTS.

from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.opc.constants import RELATIONSHIP_TYPE AS RT
from pptx.oxml.ns import nsdecls
from pptx.oxml import parse_xml

pptx = Presentation()
first_slide_layout = pptx.slide_layouts[0]

slide = pptx.slides.add_slide(first_slide_layout)

slide.shapes.title.text = "Created by Python-pptx"

pptx.save("databricks/driver/test.pptx")
####-----> until here code works.

## Below part of adding custom properties does not work.

def add_custom_properties(ppt, name, value):
        custom_property_xml = f'<properties xmlns = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties">'\
                     f'<property name = "{name}" type = "string">{value}</property>'\
                      '</properties>'
        custom_property = parse_xml(custom_property_xml)

        ppt.part.package.relate_to(custom_property, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties')

# Below command does not return any error.
add_custom_properties(pptx, "test_key", "test_key_value")

# while saving throws an error.
pptx.save("/databricks/driver/aaa.pptx")

Ошибка: file может быть либо путем к файлу, либо файловоподобным объектом, открытым для записи байтов.

Может ли кто-нибудь помочь мне понять, что не так с этим кодом?

Глядя на выделенный синтаксис код, ясно видно синтаксическую ошибку: slide.shapes.title.text = 'Created by Python-pptx" -> Строковый литерал, начинающийся с апострофа, не заканчивается двойной кавычкой. Также в определении функции add_custom_properties(ppt, name, value): -> отсутствует ключевое слово def.

Axel Richter 06.08.2024 00:38

@AxelRichter Это были всего лишь мои опечатки при публикации.

Aady 06.08.2024 00:41
from pptx.opc.constants import RELATIONSHIP_TYPE AS RT -> Что здесь AS? Вы имеете в виду as?
Axel Richter 06.08.2024 00:51

@AxelRichter Да

Aady 06.08.2024 01:22

Поэтому, пожалуйста, исправьте это. И я думаю, что упомянутая ошибка просто связана с тем, что pptx.save("/databricks/driver/aaa.pptx") ожидает каталог databricks в корневом каталоге. Разве не так должно быть pptx.save("databricks/driver/aaa.pptx")?

Axel Richter 06.08.2024 04:25
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Если оставить в стороне все простые синтаксические ошибки и неправильный путь к файлу, этот код выглядит так, как будто любой ИИ догадался об этом по каким-то другим фрагментам кода. Нет, ИИ до сих пор не умеет программировать.

Package.relate_to нужна часть пакета, а не lxml.etree как parse_xml возвращается.

И отношения – это еще не все. Сначала необходимо создать часть пакета. Python-pptx до сих пор не поддерживает часть пользовательских свойств. Таким образом, в шаблоне pptx по умолчанию такой части пакета нет. Поэтому его необходимо создать с помощью PartFactory.

Кроме того, XML элемента Properties тоже неправильный. См. пример и описания в разделе Установка пользовательского свойства в текстовом документе. Это относится к текстовому документу, но то же самое относится и к слайд-шоу презентаций.

На связанной странице Learn-Microsoft.com описано:

  • Каждое свойство в содержимом XML состоит из элемента XML, который включает имя и стоимость имущества.
  • Для каждого свойства содержимое XML включает атрибут fmtid, который всегда установлено одно и то же строковое значение: {D5CDD505-2E9C-101B-9397-08002B2CF9AE}.
  • Каждое свойство в содержимом XML включает атрибут pid, который должен включите целое число, начинающееся с 2, для первого свойства и увеличивается для каждого последующего свойства.
  • Каждое свойство отслеживает свой тип (на рисунке vt:lpwstr и vt:filetime имена элементов определяют типы каждого свойства).

Поскольку это исходит от самой Microsoft, вы не найдете более достоверного описания. Но для типов свойств я могу сказать вам по собственному сроку действия, что есть lpwstr, filetime и bool, а также i4 для целых чисел и r8 для чисел с плавающей запятой.

Следующий код работает для меня и создает aaa.pptx с тремя наборами пользовательских свойств.

from pptx import Presentation

presentation = Presentation()
first_slide_layout = presentation.slide_layouts[0]

slide = presentation.slides.add_slide(first_slide_layout)

slide.shapes.title.text = 'Created by Python-pptx'

presentation.save('./test.pptx')
####-----> until here code works.

## Below part of adding custom properties works too now.

from pptx.opc.constants import (
    RELATIONSHIP_TYPE,
    CONTENT_TYPE,
)
from pptx.opc.packuri import PackURI
from pptx.opc.package import PartFactory

def add_custom_properties(presentation, name, value, value_type):
    contains_custom_property = False
    for part in presentation.part.package.iter_parts():
        if part.partname == '/docProps/custom.xml':
            custom_property_part = part
            contains_custom_property = True
            
    pid = 2    
    if not contains_custom_property:
        custom_property_xml = '<Properties xmlns = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties" xmlns:vt = "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">'
        custom_property_xml += f'<property fmtid = "{{D5CDD505-2E9C-101B-9397-08002B2CF9AE}}" pid = "{pid}" name = "{name}">'
        custom_property_xml += f'<vt:{value_type}>{value}</vt:{value_type}>'
        custom_property_xml += '</property>'
        custom_property_xml += '</Properties>'
        
        custom_property_pack_uri = PackURI('/docProps/custom.xml')
        custom_property_content_type = CONTENT_TYPE.OFC_CUSTOM_PROPERTIES
        custom_property_part = PartFactory(custom_property_pack_uri, custom_property_content_type, presentation.part.package, custom_property_xml.encode('utf-8'))

        presentation.part.package.relate_to(custom_property_part, RELATIONSHIP_TYPE.CUSTOM_PROPERTIES)
    else:
        custom_property_xml = custom_property_part.blob.decode('utf-8')
        custom_property_xml = custom_property_xml[:-13]
        
        pid = 2 + custom_property_xml.count('<property')
        
        custom_property_xml += f'<property fmtid = "{{D5CDD505-2E9C-101B-9397-08002B2CF9AE}}" pid = "{pid}" name = "{name}">'
        custom_property_xml += f'<vt:{value_type}>{value}</vt:{value_type}>'
        custom_property_xml += '</property>'    
        custom_property_xml += '</Properties>'
        custom_property_part.blob = custom_property_xml.encode('utf-8')

add_custom_properties(presentation, "test_key", "test_key_value", "lpwstr")
add_custom_properties(presentation, "number", "1234", "i4")
add_custom_properties(presentation, "date", "2024-08-06", "filetime")

# while saving not throws any error.
presentation.save('./aaa.pptx')

Это сработало. Большое спасибо. Однако некоторые моменты я не понял. Если вы дадите несколько советов, я смогу лучше читать и понимать. Еще раз спасибо. 1. почему пид? 2. почему тип значения? 3. что это за дата?

Aady 06.08.2024 19:57

Все это можно найти на связанной странице Learn-Microsoft.com.

Axel Richter 07.08.2024 04:05

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

Источник данных databricks_metastores — я пытаюсь использовать его в Azure, чтобы узнать идентификатор хранилища метаданных. Получение ошибки: неверная конфигурация учетной записи блоков данных
Невозможно выполнить блокнот Databricks из фабрики данных Azure
Автоматическое создание соединителя доступа к единству-каталогу
Невозможно создать таблицу на подключенном диске в Databricks: для пути не найдено родительское внешнее местоположение
Data Factory Parquet неправильно принимает десятичные дроби
«Исключение: отчет Power BI не встроен» в Azure Databricks
Spark читает CSV с плохими записями
Ошибка создания блоков данных: AnalysisException: [ErrorClass=INVALID_PARAMETER_VALUE] Отсутствует схема облачной файловой системы
Невозможно создать дельта-таблицу в Databricks Premium. Нет проблем с созданием версии сообщества Delta Table Databricks
Как маскировать хэш-пользователей случайными значениями [email protected] в Azure databricks