Python Pptx 未正确捕获幻灯片母版名称

Python Pptx not capturing Slide Master Name properly

玩 Python PPTX,它似乎没有正确读取幻灯片母版名称。

你可以看到这里我重命名了幻灯片母版

它甚至会在尝试添加幻灯片时出现

但是,当我通过 pptx 加载演示文稿时,名称是 ''

In [14]: import pptx
In [15]: pres = pptx.Presentation("adsf.pptx")
In [16]: pres.slide_master.name
Out[17]: ''

也许我在幻灯片方面做错了什么。我很想知道。我正在使用 Office 2016。附带说明一下,我正在研究 xml,看起来幻灯片母版 xml 没有包含与 ooxml 中的名称属性相关的任何属性。但是主题 xml 确实如此。让我感到困惑。

感谢您的时间和努力

编辑:

毕竟我找到了我的解决方案并感谢@Scanny

import pptx
import re
from lxml import etree

# This causes pres.slide_master.layout.placeholder.name to be passed to pres.slide.placeholder
@property
def placeholder_name(self):
    """Name of the placeholder inherited from slide master"""
    return self._inherited_value("name")

def Presentation(powerpoint=None):
    """
    Return a |Presentation| object loaded from *pptx*, where *pptx* can be
    either a path to a ``.pptx`` file (a string) or a file-like object. If
    *pptx* is missing or ``None``, the built-in default presentation
    "template" is loaded.
    """
    if powerpoint is None:
        powerpoint = pptx.api._default_pptx_path()

    # get the package and not just the presentation package
    package = pptx.package.Package.open(powerpoint)

    # now extract the document
    presentation_part = package.main_document_part

    if not pptx.api._is_pptx_package(presentation_part):
        tmpl = "file '%s' is not a PowerPoint file, content type is '%s'"
        raise ValueError(tmpl % (powerpoint, presentation_part.content_type))

    # the theme names are the slide master names
    themes = (part for part in package.parts if re.search("^/ppt/theme/theme\d+\.xml$",part.partname))
    theme_names = [etree.fromstring(theme.blob).get("name") for theme in themes]


    # now get the presentation
    presentation = presentation_part.presentation

    # change the slide master names
    for idx,sld_mstr in enumerate(presentation.slide_masters):
        sld_mstr.name = theme_names[idx]


    return presentation

pptx.Presentation = Presentation
pptx.shapes.placeholder._InheritsDimensions.placeholder_name = placeholder_name
In [2]: pres = pptx.Presentation("adsf.pptx")
In [3]: for sm in pres.slide_masters: print(sm.name)
my master
number 3
my second
In [4]: layout = pres.slide_masters[0].slide_layouts[0]
In [5]: layout.name
Out[5]: 'my master title slide layout'
In [6]: new_slide = pres.slides.add_slide(layout)
In [7]: new_slide.placeholders[0].name
Out[7]: 'Title 1'
In [8]: new_slide.placeholders[0].placeholder_name
Out[8]: 'Main Title'
In [9]: pres.save("test.pptx")                             

是的,这就是我要继续的方式,在 XML 中查找字符串“my master”,看看它出现在哪里。

PowerPoint 主题包括母版和布局,因此 UI 可以计算此 rename 操作以重命名主题,这可以从 UI perspective,就像你想保存这个主题,然后通过从列表中选择这个名称来使用它。

反向操作可能有意义,意思是使用 python-pptx 设置主名称,读回它以确认,然后查看它在 UI 中出现的位置,如果有的话.


您可以直接从演示文稿进入 presentation-part:

prs = Presentation(...)
presentation_part = prs._part

所有部分都有包参考,不用自己加载:

package = presentation_part._package

但您可能不需要它,因为您可以直接从演示部分进入演示主题(而不是 Notes-pages 主题等):

from pptx.opc.constants import RELATIONSHIP_TYPE as RT

theme_rels = [rel for rel in presentation_part.rels if rel.reltype == RT.THEME]
theme_parts = [presentation_part.related_parts[rel.rId] for rel in theme_rels]

然后只需将每个主题作为 XmlPart 加载,例如:

theme_parts = [
    XmlPart.load(
        part._partname,
        part._content_type,
        part._blob,
        part._package,
    )
    for part in theme_parts
]

然后您可以在 theme_part._element 上获取主题 XML 文档的根,您可以在其上使用 lxml.etree._Element 方法来遍历该树,或者只获取根元素名称带有 theme_part._element.attribs["name"].

这只是记忆中的 aircode,但希望能给你足够的继续,一旦你到达那里,你就可以 post 工作代码。

如果你有的东西可以完成工作,那么一定要使用它,但这可能更直接,并且使用已经存在的实现,这样你就不必担心事情会出乎意料地出错:)

几乎所有的代码都在 pptx/opc/package.py.