Я пытаюсь добавить пользовательские свойства в файл 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
может быть либо путем к файлу, либо файловоподобным объектом, открытым для записи байтов.
Может ли кто-нибудь помочь мне понять, что не так с этим кодом?
Если оставить в стороне все простые синтаксические ошибки и неправильный путь к файлу, этот код выглядит так, как будто любой ИИ догадался об этом по каким-то другим фрагментам кода. Нет, ИИ до сих пор не умеет программировать.
Package.relate_to
нужна часть пакета, а не lxml.etree
как parse_xml
возвращается.
И отношения – это еще не все. Сначала необходимо создать часть пакета. Python-pptx до сих пор не поддерживает часть пользовательских свойств. Таким образом, в шаблоне pptx по умолчанию такой части пакета нет. Поэтому его необходимо создать с помощью PartFactory
.
Кроме того, XML элемента Properties
тоже неправильный. См. пример и описания в разделе Установка пользовательского свойства в текстовом документе. Это относится к текстовому документу, но то же самое относится и к слайд-шоу презентаций.
На связанной странице Learn-Microsoft.com описано:
fmtid
, который
всегда установлено одно и то же строковое значение:
{D5CDD505-2E9C-101B-9397-08002B2CF9AE}.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')