A slide carries a companion notes slide part with speaker-notes text in its body placeholder.
Library verdicts: python-pptx: — pptxjs: fail
| Feature id | pptx/slide-notes |
|---|---|
| Format | pptx |
| Category | slide-content |
| Spec | ecma-376-5-part-1 § 19.3.1.26 p:notes |
| ID / part | Predicate | XPath | python-pptx | pptxjs |
|---|---|---|---|---|
notes-slide-part-existsppt/notesSlides/notesSlide1.xml | existA notes slide part must exist at ppt/notesSlides/notesSlide1.xml with a <p:notes> root element. | /p:notes | — | — |
notes-slide-text-presentppt/notesSlides/notesSlide1.xml | existThe notes slide's text body must carry a run whose value is 'These are speaker notes'. | //a:t[normalize-space()='These are speaker notes'] | — | — |
| ID | Predicate | Selector | python-pptx | pptxjs |
|---|---|---|---|---|
notes-dom-present | css_selector/ existA 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-count | css_selector/ equal-countExactly 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] | — | — |
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()){
"$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."
}
]
}
