pptx/slide-notes

A slide carries a companion notes slide part with speaker-notes text in its body placeholder.

Library verdicts: python-pptx: — pptxjs: fail

Metadata

Feature idpptx/slide-notes
Formatpptx
Categoryslide-content
Spececma-376-5-part-1 § 19.3.1.26 p:notes

XPath assertions

ID / partPredicateXPathpython-pptxpptxjs
notes-slide-part-exists
ppt/notesSlides/notesSlide1.xml
exist
A notes slide part must exist at ppt/notesSlides/notesSlide1.xml with a <p:notes> root element.
/p:notes
notes-slide-text-present
ppt/notesSlides/notesSlide1.xml
exist
The notes slide's text body must carry a run whose value is 'These are speaker notes'.
//a:t[normalize-space()='These are speaker notes']

Render assertions

IDPredicateSelectorpython-pptxpptxjs
notes-dom-presentcss_selector/ exist
A DOM node annotated as notes must exist. Many renderers (including pptxjs) do not render notes by default, so this check frequently fails — the resulting gap is an accurate reflection of rendering-side support.
.pptx-notes, [data-notes]fail
slide-countcss_selector/ equal-count
Exactly one slide container must be rendered. Catches renderers that emit zero slides (hard failure) or duplicate the slide.
section.pptx-slide, .pptx-slide, section[data-slide], .slide, [data-slide]

Generator source

scripts/gen_slide_notes.py

#!/usr/bin/env python3
"""Generate ``fixtures/pptx/slide-notes.pptx``.

A one-slide presentation with speaker notes attached. Accessing
``slide.notes_slide`` forces creation of ``ppt/notesSlides/notesSlide1.xml``.
Designed to satisfy the assertions in ``features/pptx/slide-notes.json``.
"""

from __future__ import annotations

from pathlib import Path

from pptx import Presentation

import datetime as _dt
_REPRODUCIBLE_DT = _dt.datetime(2000, 1, 1, 0, 0, 0)

_REPO_ROOT = Path(__file__).resolve().parent.parent
_OUT = _REPO_ROOT / "fixtures" / "pptx" / "slide-notes.pptx"


def main() -> int:
    prs = Presentation()
    slide = prs.slides.add_slide(prs.slide_layouts[0])
    slide.shapes.title.text = "Slide with notes"
    slide.notes_slide.notes_text_frame.text = "These are speaker notes"

    _OUT.parent.mkdir(parents=True, exist_ok=True)
    prs.save(_OUT, zip_date_time=_REPRODUCIBLE_DT)
    print(_OUT)
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Manifest (expanded)

{
  "$schema": "../manifest.schema.json",
  "id": "pptx/slide-notes",
  "title": "Speaker notes on a slide",
  "format": "pptx",
  "category": "slide-content",
  "summary": "A slide carries a companion notes slide part with speaker-notes text in its body placeholder.",
  "spec": {
    "source": "ecma-376-5-part-1",
    "clause": "19.3.1.26",
    "element": "p:notes",
    "rnc_reference": "spec/ecma-376-5/part-1/rnc/PresentationML.rnc",
    "xsd_reference": "spec/ecma-376-5/part-1/xsd/pml.xsd",
    "notes": "Speaker notes live in a separate notesSlide part (ppt/notesSlides/notesSlide1.xml). python-pptx emits the notes body as a <p:sp> with <p:ph type=\"body\" idx=\"3\" sz=\"quarter\"/>. Many renderers do not display notes by default; the accompanying render assertion is therefore a best-effort exist check that tolerates a missing DOM node."
  },
  "fixtures": {
    "machine": "pptx/slide-notes",
    "office": "pptx/slide-notes"
  },
  "generator": {
    "python": "scripts/gen_slide_notes.py"
  },
  "assertions": [
    {
      "id": "notes-slide-part-exists",
      "part": "ppt/notesSlides/notesSlide1.xml",
      "namespaces": {
        "p": "http://schemas.openxmlformats.org/presentationml/2006/main",
        "a": "http://schemas.openxmlformats.org/drawingml/2006/main"
      },
      "xpath": "/p:notes",
      "must": "exist",
      "description": "A notes slide part must exist at ppt/notesSlides/notesSlide1.xml with a <p:notes> root element."
    },
    {
      "id": "notes-slide-text-present",
      "part": "ppt/notesSlides/notesSlide1.xml",
      "namespaces": {
        "p": "http://schemas.openxmlformats.org/presentationml/2006/main",
        "a": "http://schemas.openxmlformats.org/drawingml/2006/main"
      },
      "xpath": "//a:t[normalize-space()='These are speaker notes']",
      "must": "exist",
      "description": "The notes slide's text body must carry a run whose value is 'These are speaker notes'."
    }
  ],
  "render_assertions": [
    {
      "id": "notes-dom-present",
      "kind": "css_selector",
      "selector": ".pptx-notes, [data-notes]",
      "must": "exist",
      "description": "A DOM node annotated as notes must exist. Many renderers (including pptxjs) do not render notes by default, so this check frequently fails — the resulting gap is an accurate reflection of rendering-side support."
    },
    {
      "id": "slide-count",
      "kind": "css_selector",
      "selector": "section.pptx-slide, .pptx-slide, section[data-slide], .slide, [data-slide]",
      "must": "equal-count",
      "count": 1,
      "description": "Exactly one slide container must be rendered. Catches renderers that emit zero slides (hard failure) or duplicate the slide."
    }
  ]
}

Fixture

Download slide-notes.pptx (32.0 KB)

Reference preview

Reference (machine, page 1 PNG)

pptx/slide-notes page 1 reference

Reference PDF


Download PDF Open in PDF.js

Spec notes

Speaker notes live in a separate notesSlide part (ppt/notesSlides/notesSlide1.xml). python-pptx emits the notes body as a <p:sp> with <p:ph type="body" idx="3" sz="quarter"/>. Many renderers do not display notes by default; the accompanying render assertion is therefore a best-effort exist check that tolerates a missing DOM node.