Open bullet-list.pptx (1 slide) and append a new slide via prs.slides.add_slide(prs.slide_layouts[1]) (Title and Content layout). Assert (a) the presentation now references 2 slides, (b) ppt/slides/slide2.xml is present, and (c) slide1.xml's original text content (the 'Bullets' title and three bullet items) is byte-preserved.
Library verdicts: python-pptx: — pptxjs: —
| Feature id | pptx/modify-add-slide |
|---|---|
| Format | pptx |
| Category | modify-in-place |
| Spec | ecma-376-5-part-1 § 13.3.8 p:sldIdLst |
| ID / part | Predicate | XPath | python-pptx | pptxjs |
|---|---|---|---|---|
presentation-has-two-slide-refsppt/presentation.xml | match = ^2(\.0+)?$sldIdLst must now reference 2 slides (was 1). | count(/p:presentation/p:sldIdLst/p:sldId) | — | — |
first-slide-id-preservedppt/presentation.xml | equal = 256The original slide's id (256) must be preserved. | /p:presentation/p:sldIdLst/p:sldId[1]/@id | — | — |
original-slide1-title-preservedppt/slides/slide1.xml | existSlide1's 'Bullets' title must still be present — adding slide2 must not touch slide1. | //a:t[normalize-space()='Bullets'] | — | — |
original-slide1-bullet-oneppt/slides/slide1.xml | existSlide1's first bullet 'Item one' must still be present. | //a:t[normalize-space()='Item one'] | — | — |
original-slide1-bullet-twoppt/slides/slide1.xml | existSlide1's second bullet 'Item two' must still be present. | //a:t[normalize-space()='Item two'] | — | — |
original-slide1-bullet-threeppt/slides/slide1.xml | existSlide1's third bullet 'Item three' must still be present. | //a:t[normalize-space()='Item three'] | — | — |
new-slide2-presentppt/slides/slide2.xml | existppt/slides/slide2.xml must be present and parse as a valid <p:sld>. | /p:sld | — | — |
new-slide2-is-sp-treeppt/slides/slide2.xml | existSlide2 must carry a p:spTree (shape tree). | /p:sld/p:cSld/p:spTree | — | — |
content-types-includes-slide2[Content_Types].xml | exist[Content_Types].xml must carry an Override for the new slide2 part. | /ct:Types/ct:Override[@PartName='/ppt/slides/slide2.xml'] | — | — |
No render assertions declared.
scripts/gen_modify_add_slide.py
#!/usr/bin/env python3
"""Generate ``fixtures/pptx/bullet-list--add-slide.pptx``.
Thin wrapper around ``scripts.mutations.pptx_add_slide``. Opens
``fixtures/pptx/bullet-list.pptx``, appends a slide via the
'Title and Content' layout, saves. Satisfies
``features/pptx/modify-add-slide.json``.
"""
from __future__ import annotations
from pathlib import Path
from mutations import pptx_add_slide
_REPO_ROOT = Path(__file__).resolve().parent.parent
_IN = _REPO_ROOT / "fixtures" / "pptx" / "bullet-list.pptx"
_OUT = _REPO_ROOT / "fixtures" / "pptx" / "bullet-list--add-slide.pptx"
def main() -> int:
pptx_add_slide(_IN, _OUT)
print(_OUT)
return 0
if __name__ == "__main__":
raise SystemExit(main())
{
"$schema": "../manifest.schema.json",
"id": "pptx/modify-add-slide",
"title": "Modify: add a slide to existing .pptx",
"format": "pptx",
"category": "modify-in-place",
"summary": "Open bullet-list.pptx (1 slide) and append a new slide via prs.slides.add_slide(prs.slide_layouts[1]) (Title and Content layout). Assert (a) the presentation now references 2 slides, (b) ppt/slides/slide2.xml is present, and (c) slide1.xml's original text content (the 'Bullets' title and three bullet items) is byte-preserved.",
"roles": [
"authoring"
],
"spec": {
"source": "ecma-376-5-part-1",
"clause": "13.3.8",
"element": "p:sldIdLst",
"rnc_reference": "spec/ecma-376-5/part-1/rnc/PresentationML.rnc",
"xsd_reference": "spec/ecma-376-5/part-1/xsd/pml.xsd",
"notes": "Adding a slide adds a child to p:sldIdLst in presentation.xml, a new ppt/slides/slideN.xml part, and a new relationship in ppt/_rels/presentation.xml.rels pointing at it. Existing slide parts must remain byte-identical."
},
"fixtures": {
"machine": "pptx/bullet-list--add-slide"
},
"modify": {
"input_fixture": "fixtures/pptx/bullet-list.pptx",
"mutation": "pptx_add_slide",
"output_fixture": "fixtures/pptx/bullet-list--add-slide.pptx"
},
"generator": {
"python": "scripts/gen_modify_add_slide.py"
},
"assertions": [
{
"id": "presentation-has-two-slide-refs",
"part": "ppt/presentation.xml",
"namespaces": {
"p": "http://schemas.openxmlformats.org/presentationml/2006/main"
},
"xpath": "count(/p:presentation/p:sldIdLst/p:sldId)",
"must": "match",
"value": "^2(\\.0+)?$",
"description": "sldIdLst must now reference 2 slides (was 1)."
},
{
"id": "first-slide-id-preserved",
"part": "ppt/presentation.xml",
"namespaces": {
"p": "http://schemas.openxmlformats.org/presentationml/2006/main"
},
"xpath": "/p:presentation/p:sldIdLst/p:sldId[1]/@id",
"must": "equal",
"value": "256",
"description": "The original slide's id (256) must be preserved."
},
{
"id": "original-slide1-title-preserved",
"part": "ppt/slides/slide1.xml",
"namespaces": {
"a": "http://schemas.openxmlformats.org/drawingml/2006/main"
},
"xpath": "//a:t[normalize-space()='Bullets']",
"must": "exist",
"description": "Slide1's 'Bullets' title must still be present — adding slide2 must not touch slide1."
},
{
"id": "original-slide1-bullet-one",
"part": "ppt/slides/slide1.xml",
"namespaces": {
"a": "http://schemas.openxmlformats.org/drawingml/2006/main"
},
"xpath": "//a:t[normalize-space()='Item one']",
"must": "exist",
"description": "Slide1's first bullet 'Item one' must still be present."
},
{
"id": "original-slide1-bullet-two",
"part": "ppt/slides/slide1.xml",
"namespaces": {
"a": "http://schemas.openxmlformats.org/drawingml/2006/main"
},
"xpath": "//a:t[normalize-space()='Item two']",
"must": "exist",
"description": "Slide1's second bullet 'Item two' must still be present."
},
{
"id": "original-slide1-bullet-three",
"part": "ppt/slides/slide1.xml",
"namespaces": {
"a": "http://schemas.openxmlformats.org/drawingml/2006/main"
},
"xpath": "//a:t[normalize-space()='Item three']",
"must": "exist",
"description": "Slide1's third bullet 'Item three' must still be present."
},
{
"id": "new-slide2-present",
"part": "ppt/slides/slide2.xml",
"namespaces": {
"p": "http://schemas.openxmlformats.org/presentationml/2006/main"
},
"xpath": "/p:sld",
"must": "exist",
"description": "ppt/slides/slide2.xml must be present and parse as a valid <p:sld>."
},
{
"id": "new-slide2-is-sp-tree",
"part": "ppt/slides/slide2.xml",
"namespaces": {
"p": "http://schemas.openxmlformats.org/presentationml/2006/main"
},
"xpath": "/p:sld/p:cSld/p:spTree",
"must": "exist",
"description": "Slide2 must carry a p:spTree (shape tree)."
},
{
"id": "content-types-includes-slide2",
"part": "[Content_Types].xml",
"namespaces": {
"ct": "http://schemas.openxmlformats.org/package/2006/content-types"
},
"xpath": "/ct:Types/ct:Override[@PartName='/ppt/slides/slide2.xml']",
"must": "exist",
"description": "[Content_Types].xml must carry an Override for the new slide2 part."
}
]
}
No rendered reference is available for this case.