使用 Python 在演示文稿中管理标签和自定义数据
概述
本文档说明了 Aspose.Slides 如何在 PowerPoint 演示文稿中使用标签和自定义数据。演示文稿特定的数据可以存储为标签或自定义 XML 部分。标签是简单的键值字符串对,而自定义 XML 部分可以存储结构化的元数据和应用程序特定的 XML 负载。
Aspose.Slides 提供了在演示文稿、幻灯片和形状级别添加、读取、更新、审计和删除自定义 XML 部分的 API。自定义 XML 部分对于存储诸如文档管理标识符、工作流状态、合规元数据、模板绑定数据或其他结构化应用程序数据等信息的集成非常有用。
演示文稿文件中的数据存储
PPTX 文件——扩展名为 .pptx 的文件——采用 PresentationML 格式存储,这是一部分 Office Open XML 规范。Office Open XML 定义了用于存储演示文稿内容及相关数据的包结构和关系。
一个演示文稿包含多个通过关系相连的部分。例如,幻灯片部分包含单个幻灯片的内容,并且可以通过 ISO/IEC 29500 定义的显式关系链接到其他部分。
自定义数据可以作为标签(TagCollection)或自定义 XML 部分(CustomXmlPartCollection)存储。两者均通过 CustomData 类访问。
Note
标签存储简单的字符串键值对。自定义 XML 部分存储结构化的 XML 数据,并且可以关联到演示文稿、幻灯片或形状。使用自定义 XML 部分
CustomData.getCustomXmlParts 方法返回与特定演示文稿对象关联的自定义 XML 部分集合。例如:
- 演示文稿的 CustomData.getCustomXmlParts 集合包含与演示文稿本身关联的自定义 XML 部分。
- 幻灯片的 CustomData.getCustomXmlParts 集合包含与特定幻灯片关联的自定义 XML 部分。
- 形状的 CustomData.getCustomXmlParts 集合包含与特定形状关联的自定义 XML 部分。
当需要检查演示文稿中所有自定义 XML 部分(不论其关联对象)时,请使用 Presentation.getAllCustomXmlParts。
向演示文稿添加自定义 XML 部分
使用 CustomXmlPartCollection.add 将 XML 数据添加到自定义 XML 部分集合中。XML 必须有效且非空。
以下示例向演示文稿级别的自定义数据集合添加结构化元数据:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import Presentation, SaveFormat
from java.util import UUID
presentation = Presentation()
try:
custom_xml_content = '<?xml version="1.0" encoding="UTF-8"?><metadata xmlns="urn:example:metadata"><documentId>DOC-1001</documentId><workflowState>Draft</workflowState></metadata>'
custom_xml_part = presentation.getCustomData().getCustomXmlParts().add(custom_xml_content)
# add 会自动分配标识符。仅在需要时才设置特定的 UUID。
item_id = UUID.randomUUID()
custom_xml_part.setItemId(item_id)
presentation.save("presentation_with_custom_xml.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
add 方法还可以接受 XML 的字节数组或输入流,这在 XML 内容已经以二进制形式存在时非常有用。
向幻灯片或形状添加自定义 XML 部分
自定义 XML 数据可以关联到特定幻灯片或形状,而不是整个演示文稿。当元数据仅描述单个对象(例如模板键、外部记录标识符或绑定信息)时,这非常有用。
以下示例向一个幻灯片添加一个自定义 XML 部分,并向一个形状添加另一个:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import Presentation, SaveFormat, ShapeType
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(0)
slide_xml_content = '<slideMetadata xmlns="urn:example:slides"><templateKey>TitleSlide</templateKey></slideMetadata>'
slide.getCustomData().getCustomXmlParts().add(slide_xml_content)
shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 50, 50, 250, 80)
shape.getTextFrame().setText("Customer data")
shape_xml_content = '<shapeMetadata xmlns="urn:example:shapes"><recordId>CRM-4281</recordId></shapeMetadata>'
shape.getCustomData().getCustomXmlParts().add(shape_xml_content)
presentation.save("object_custom_xml.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
添加部分的层级决定了哪个对象的 CustomData.getCustomXmlParts 集合包含对该部分的关系。演示文稿级别的数据适用于全局元数据,幻灯片级别的数据适用于特定幻灯片的信息,形状级别的数据适用于单个形状的元数据。
列出并审计所有自定义 XML 部分
使用 Presentation.getAllCustomXmlParts 检索演示文稿中的所有自定义 XML 部分。每个 CustomXmlPart 都会暴露其标识符、XML 内容以及关联的命名空间架构。
以下示例列出所有自定义 XML 部分及其命名空间架构:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import Presentation
presentation = Presentation("presentation.pptx")
try:
for custom_xml_part in presentation.getAllCustomXmlParts():
print("ItemId:", custom_xml_part.getItemId())
print("XML:")
print(custom_xml_part.getXmlAsString())
for namespace_schema in custom_xml_part.getNamespaceSchemas():
print("Namespace schema:", namespace_schema)
print()
finally:
presentation.dispose()
CustomXmlPart.getNamespaceSchemas 返回与自定义 XML 部分关联的 XML 架构。当审计包含外部系统生成的 XML 的演示文稿时,此信息可能非常有用。
读取并更新 XML 内容和 ItemId
使用 CustomXmlPart.getXmlAsString 和 setXmlAsString 以 UTF-8 字符串形式处理 XML,或使用 getXmlData 和 setXmlData 以原始字节形式处理。
CustomXmlPart.getItemId 方法返回标识该自定义 XML 部分在 Office Open XML 文档中的 UUID。需要新标识符时,请使用 setItemId。
以下示例更新 XML 内容和标识符:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import Presentation, SaveFormat
from java.util import UUID
presentation = Presentation("presentation.pptx")
try:
custom_xml_parts = presentation.getAllCustomXmlParts()
if len(custom_xml_parts) > 0:
custom_xml_part = custom_xml_parts[0]
# 读取当前的 XML 文本。
current_xml_content = custom_xml_part.getXmlAsString()
print(current_xml_content)
# 将 XML 更新为 UTF-8 字符串。
custom_xml_content = '<metadata xmlns="urn:example:metadata"><documentId>DOC-1001</documentId><workflowState>Approved</workflowState></metadata>'
custom_xml_part.setXmlAsString(custom_xml_content)
# getXmlData 提供相同的 XML 内容,以原始字节形式。
custom_xml_data = custom_xml_part.getXmlData()
print(bytes(custom_xml_data).decode("utf-8"))
# 在集成需要时替换标识符。
item_id = UUID.randomUUID()
custom_xml_part.setItemId(item_id)
presentation.save("updated_custom_xml.pptx", SaveFormat.Pptx)
else:
print("No custom XML parts found.")
finally:
presentation.dispose()
在调用 setXmlAsString 或 setXmlData 时,提供有效且非空的 XML。根据应用程序是主要处理字符串还是字节数据,选择其中一种表示方式。
删除自定义 XML 部分
Aspose.Slides 提供多种方式删除自定义 XML 数据:
- CustomXmlPart.remove 从演示文稿中删除该自定义 XML 部分。
- CustomXmlPartCollection.remove 从自定义 XML 部分集合中删除特定部分。
- CustomXmlPartCollection.removeAt 删除指定集合索引处的部分。
- CustomXmlPartCollection.clear 删除特定集合中的所有部分。
以下示例通过引用删除一个演示文稿级别的自定义 XML 部分:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import Presentation, SaveFormat
presentation = Presentation("presentation.pptx")
try:
custom_xml_parts = presentation.getCustomData().getCustomXmlParts()
if custom_xml_parts.size() > 0:
custom_xml_part = custom_xml_parts.get_Item(0)
custom_xml_parts.remove(custom_xml_part)
presentation.save("custom_xml_removed.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
如果已有 CustomXmlPart 并希望从演示文稿中删除该部分,而不是针对特定集合,请调用 CustomXmlPart.remove。
也可以按索引删除项目:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import Presentation
presentation = Presentation("presentation.pptx")
try:
custom_xml_parts = presentation.getCustomData().getCustomXmlParts()
if custom_xml_parts.size() > 0:
custom_xml_parts.removeAt(0)
finally:
presentation.dispose()
清除集合中的所有自定义 XML 部分
当需要删除与特定演示文稿对象关联的所有自定义 XML 部分时,使用 clear。
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import Presentation, SaveFormat
presentation = Presentation("presentation.pptx")
try:
presentation.getSlides().get_Item(0).getCustomData().getCustomXmlParts().clear()
presentation.save("slide_custom_xml_cleared.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
clear 仅影响选定的集合。例如,清除幻灯片的集合不会清除演示文稿级或形状级的集合。
要删除演示文稿中的所有自定义 XML 部分,可遍历 getAllCustomXmlParts 并删除每个部分:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import Presentation, SaveFormat
presentation = Presentation("presentation.pptx")
try:
for custom_xml_part in presentation.getAllCustomXmlParts():
custom_xml_part.remove()
presentation.save("all_custom_xml_removed.pptx", SaveFormat.Pptx)
finally:
presentation.dispose()
处理链接或共享的自定义 XML 部分
在 Office Open XML 演示文稿中,同一个自定义 XML 部分可能被多个演示文稿对象引用。例如,一个文件可以包含来自多个幻灯片或形状指向同一底层自定义 XML 部分的关系。
共享的部分应视为一个数据对象,但具有多个引用:
- 使用 setXmlAsString、setXmlData 或 setItemId 更新它时,会更改底层自定义 XML 部分,从而在所有引用该部分的地方生效。
- getItemId 可用于在审计对象级集合时识别相同的自定义 XML 部分。
- 从特定的 getCustomXmlParts 集合中删除部分,只会将其从该集合中移除。若要从演示文稿中完全删除该部分,请使用 CustomXmlPart.remove。
- 在删除或替换共享部分之前,检查对象级集合,以确定是否还有其他幻灯片或形状引用该部分。
add 重载会从 XML 内容创建新的自定义 XML 部分;它们不接受已有的 CustomXmlPart。因此,加载已经包含共享关系的演示文稿时最常遇到共享关系。
以下示例按 ItemId 审计演示文稿、幻灯片和形状级别的集合,并报告被多个位置引用的部分:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import Presentation
presentation = Presentation("presentation.pptx")
try:
references_by_item_id = {}
def register_custom_xml_parts(owner_name, custom_xml_parts):
for i in range(custom_xml_parts.size()):
custom_xml_part = custom_xml_parts.get_Item(i)
item_id = str(custom_xml_part.getItemId())
references_by_item_id.setdefault(item_id, []).append(owner_name)
register_custom_xml_parts("Presentation", presentation.getCustomData().getCustomXmlParts())
for slide_index in range(presentation.getSlides().size()):
slide = presentation.getSlides().get_Item(slide_index)
register_custom_xml_parts(f"Slide {slide_index + 1}", slide.getCustomData().getCustomXmlParts())
for shape_index in range(slide.getShapes().size()):
shape = slide.getShapes().get_Item(shape_index)
register_custom_xml_parts(f"Slide {slide_index + 1}, shape {shape_index}", shape.getCustomData().getCustomXmlParts())
for item_id, owner_names in references_by_item_id.items():
if len(owner_names) > 1:
print("Shared custom XML part:", item_id)
for owner_name in owner_names:
print(" Referenced by:", owner_name)
finally:
presentation.dispose()
此类审计在修改或删除由外部系统创建的演示文稿中的自定义 XML 数据之前非常有用,因为同一元数据部分可能参与多个关系。
获取标签的值
在 Slides 中,标签对应于 DocumentProperties.getKeywords 方法。以下示例代码展示了如何使用 Aspose.Slides for Python via Java 获取 Presentation 中的标签值:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import Presentation
presentation = Presentation("presentation.pptx")
try:
keywords = presentation.getDocumentProperties().getKeywords()
finally:
presentation.dispose()
向演示文稿添加标签
Aspose.Slides 允许向演示文稿添加标签。标签通常由两项组成:
- 自定义属性的名称,例如
MyTag; - 自定义属性的值,例如
My Tag Value。
如果需要根据特定规则或属性对演示文稿进行分类,可以添加相应的标签。例如,要对来自北美国家的演示文稿进行分类,可创建一个北美标签并将相应的国家名称作为其值。
以下示例代码展示了如何使用 Aspose.Slides for Python via Java 向 Presentation 添加标签:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import Presentation
presentation = Presentation("presentation.pptx")
try:
tags = presentation.getCustomData().getTags()
tags.set_Item("MyTag", "My Tag Value")
finally:
presentation.dispose()
标签也可以为 Slide 设置:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import Presentation
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(0)
slide.getCustomData().getTags().set_Item("tag", "value")
finally:
presentation.dispose()
或为单个 Shape 设置:
import jpype
import asposeslides
if not jpype.isJVMStarted():
jpype.startJVM()
from asposeslides.api import Presentation, ShapeType
presentation = Presentation()
try:
slide = presentation.getSlides().get_Item(0)
shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 10, 10, 100, 50)
shape.getTextFrame().setText("My text")
shape.getCustomData().getTags().set_Item("tag", "value")
finally:
presentation.dispose()
限制
通过 CustomData.getTags 集合添加的标签仅存储在 PowerPoint 文件中。导出为 PDF 时,它们 不会 转移到 PDF 的标签结构中。因此,作为标签分配的自定义标识符无法从带标签的 PDF 中检索。
解决办法:可以将自定义标识符存储在对象的 Alt Text 中(例如,使用 Shape.setAlternativeText 并设置值 "MyId")。导出为 PDF 后,Alt Text 可能会出现在 PDF 的标签结构中。
常见问题解答
是否可以一次性删除演示文稿、幻灯片或形状中的所有标签?
可以。标签集合(tag collection)支持 clear 操作,一次性删除所有键值对。
如何在不遍历整个集合的情况下,仅通过名称删除单个标签?
在标签集合上使用 remove 并传入键即可删除对应的标签。
如何获取完整的标签名称列表以进行分析或过滤?
使用标签集合的 getNamesOfTags 方法,它返回所有标签名称的数组。
如何找到所有自定义 XML 部分,而不论它们存储在哪里?
使用 Presentation.getAllCustomXmlParts 检索演示文稿中的全部自定义 XML 部分。
在更新自定义 XML 部分时,我应使用 [getXmlAsString]/[setXmlAsString] 还是 [getXmlData]/[setXmlData]?
当应用程序使用 UTF-8 XML 文本时,使用 getXmlAsString 和 setXmlAsString。当 XML 已以字节数组形式存在或二进制处理更方便时,使用 getXmlData 和 setXmlData。两种表示方式都指向同一自定义 XML 部分的内容。