pptx/modify-add-slide

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: —

Metadata

Feature idpptx/modify-add-slide
Formatpptx
Categorymodify-in-place
Spececma-376-5-part-1 § 13.3.8 p:sldIdLst

XPath assertions

ID / partPredicateXPathpython-pptxpptxjs
presentation-has-two-slide-refs
ppt/presentation.xml
match = ^2(\.0+)?$
sldIdLst must now reference 2 slides (was 1).
count(/p:presentation/p:sldIdLst/p:sldId)
first-slide-id-preserved
ppt/presentation.xml
equal = 256
The original slide's id (256) must be preserved.
/p:presentation/p:sldIdLst/p:sldId[1]/@id
original-slide1-title-preserved
ppt/slides/slide1.xml
exist
Slide1's 'Bullets' title must still be present — adding slide2 must not touch slide1.
//a:t[normalize-space()='Bullets']
original-slide1-bullet-one
ppt/slides/slide1.xml
exist
Slide1's first bullet 'Item one' must still be present.
//a:t[normalize-space()='Item one']
original-slide1-bullet-two
ppt/slides/slide1.xml
exist
Slide1's second bullet 'Item two' must still be present.
//a:t[normalize-space()='Item two']
original-slide1-bullet-three
ppt/slides/slide1.xml
exist
Slide1's third bullet 'Item three' must still be present.
//a:t[normalize-space()='Item three']
new-slide2-present
ppt/slides/slide2.xml
exist
ppt/slides/slide2.xml must be present and parse as a valid <p:sld>.
/p:sld
new-slide2-is-sp-tree
ppt/slides/slide2.xml
exist
Slide2 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']

Render assertions

No render assertions declared.

Generator source

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())

Manifest (expanded)

{
  "$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."
    }
  ]
}

Fixture

Download bullet-list--add-slide.pptx (28.3 KB)

Reference preview

No rendered reference is available for this case.

Spec 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.