A run on slide 1 carries an a:hlinkClick that jumps to slide 2 when clicked in slide-show mode. The click-action is identified by action='ppaction://hlinksldjump' and resolved via an internal package relationship (TargetMode absent), distinguishing it from external-URL hyperlinks.
Library verdicts: python-pptx: — pptxjs: —
| Feature id | pptx/hyperlink-slide-jump |
|---|---|
| Format | pptx |
| Category | references |
| Spec | ecma-376-5-part-1 § 21.1.2.3.5 a:hlinkClick |
| ID / part | Predicate | XPath | python-pptx | pptxjs |
|---|---|---|---|---|
hlinkclick-action-is-sldjumpppt/slides/slide1.xml | equal = ppaction://hlinksldjumpThe click-action on the run must be identified by the ppaction://hlinksldjump URI. | string(//a:hlinkClick/@action) | — | — |
hlinkclick-has-ridppt/slides/slide1.xml | existThe slide-jump click-action must carry an r:id pointing at the internal slide relationship. | //a:hlinkClick[@r:id and @action='ppaction://hlinksldjump'] | — | — |
slide-rel-type-is-slideppt/slides/_rels/slide1.xml.rels | existThere must be a <Relationship Type='.../slide' Target='slide2.xml'/> entry in slide1's rels file. | //pr:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide' and @Target='slide2.xml'] | — | — |
slide-rel-is-internal-no-targetmodeppt/slides/_rels/slide1.xml.rels | equal = Slide-jump relationships are INTERNAL: they must not carry TargetMode='External'. This assertion fails if TargetMode is present at all -- string() of a non-existent attribute is the empty string. | string(//pr:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide' and @Target='slide2.xml']/@TargetMode) | — | — |
no-hyperlink-rel-leaks-into-slideppt/slides/_rels/slide1.xml.rels | absentA slide-jump must NOT be modelled as an external-hyperlink relationship. If this assertion fails the library is confusing internal slide jumps with external URLs. | //pr:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink'] | — | — |
No render assertions declared.
scripts/gen_hyperlink_slide_jump.py
#!/usr/bin/env python3
"""Generate ``fixtures/pptx/hyperlink-slide-jump.pptx``.
A two-slide presentation where a run of text on slide 1 is decorated
with a click-action that jumps to slide 2. The action URI is
``ppaction://hlinksldjump`` and the jump target is resolved via an
INTERNAL package relationship (Type=.../slide, no TargetMode) --
distinct from the external-URL hyperlink case which uses
Type=.../hyperlink and TargetMode='External'.
Uses python-pptx's ``run.hyperlink.target_slide = slide`` high-level
API.
.. versionadded:: 2026.05.0
"""
from __future__ import annotations
import datetime as _dt
from pathlib import Path
from pptx import Presentation
from pptx.util import Inches
_REPO_ROOT = Path(__file__).resolve().parent.parent
_OUT = _REPO_ROOT / "fixtures" / "pptx" / "hyperlink-slide-jump.pptx"
_REPRODUCIBLE_DT = _dt.datetime(2000, 1, 1, 0, 0, 0)
def main() -> int:
prs = Presentation()
slide1 = prs.slides.add_slide(prs.slide_layouts[5]) # Title Only
slide2 = prs.slides.add_slide(prs.slide_layouts[5])
textbox = slide1.shapes.add_textbox(Inches(1), Inches(2), Inches(6), Inches(1))
paragraph = textbox.text_frame.paragraphs[0]
run = paragraph.add_run()
run.text = "Jump to slide 2"
# -- the high-level API: issues a Type=.../slide rel + hlinkClick with
# -- action='ppaction://hlinksldjump' in one go.
run.hyperlink.target_slide = slide2
_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/hyperlink-slide-jump",
"title": "Slide-jump click-action hyperlink",
"format": "pptx",
"category": "references",
"summary": "A run on slide 1 carries an a:hlinkClick that jumps to slide 2 when clicked in slide-show mode. The click-action is identified by action='ppaction://hlinksldjump' and resolved via an internal package relationship (TargetMode absent), distinguishing it from external-URL hyperlinks.",
"spec": {
"source": "ecma-376-5-part-1",
"clause": "21.1.2.3.5",
"element": "a:hlinkClick",
"rnc_reference": "spec/ecma-376-5/part-1/rnc/DrawingML.rnc",
"xsd_reference": "spec/ecma-376-5/part-1/xsd/dml-main.xsd",
"notes": "PowerPoint's 'Place in This Document' hyperlink target uses the a:hlinkClick element with action='ppaction://hlinksldjump'. The a:hlinkClick/@r:id attribute resolves to a <Relationship Type='.../slide' Target='slide2.xml'/> in the slide's rels. Critically the slide-jump relationship has NO TargetMode attribute -- it is an INTERNAL package relationship, unlike external hyperlinks which require TargetMode='External'. This distinction is what separates hyperlink-slide-jump from a run-level external-URL hyperlink."
},
"fixtures": {
"machine": "pptx/hyperlink-slide-jump"
},
"generator": {
"python": "scripts/gen_hyperlink_slide_jump.py"
},
"assertions": [
{
"id": "hlinkclick-action-is-sldjump",
"part": "ppt/slides/slide1.xml",
"namespaces": {
"a": "http://schemas.openxmlformats.org/drawingml/2006/main",
"r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
},
"xpath": "string(//a:hlinkClick/@action)",
"must": "equal",
"value": "ppaction://hlinksldjump",
"description": "The click-action on the run must be identified by the ppaction://hlinksldjump URI."
},
{
"id": "hlinkclick-has-rid",
"part": "ppt/slides/slide1.xml",
"namespaces": {
"a": "http://schemas.openxmlformats.org/drawingml/2006/main",
"r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships"
},
"xpath": "//a:hlinkClick[@r:id and @action='ppaction://hlinksldjump']",
"must": "exist",
"description": "The slide-jump click-action must carry an r:id pointing at the internal slide relationship."
},
{
"id": "slide-rel-type-is-slide",
"part": "ppt/slides/_rels/slide1.xml.rels",
"namespaces": {
"pr": "http://schemas.openxmlformats.org/package/2006/relationships"
},
"xpath": "//pr:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide' and @Target='slide2.xml']",
"must": "exist",
"description": "There must be a <Relationship Type='.../slide' Target='slide2.xml'/> entry in slide1's rels file."
},
{
"id": "slide-rel-is-internal-no-targetmode",
"part": "ppt/slides/_rels/slide1.xml.rels",
"namespaces": {
"pr": "http://schemas.openxmlformats.org/package/2006/relationships"
},
"xpath": "string(//pr:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide' and @Target='slide2.xml']/@TargetMode)",
"must": "equal",
"value": "",
"description": "Slide-jump relationships are INTERNAL: they must not carry TargetMode='External'. This assertion fails if TargetMode is present at all -- string() of a non-existent attribute is the empty string."
},
{
"id": "no-hyperlink-rel-leaks-into-slide",
"part": "ppt/slides/_rels/slide1.xml.rels",
"namespaces": {
"pr": "http://schemas.openxmlformats.org/package/2006/relationships"
},
"xpath": "//pr:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink']",
"must": "absent",
"description": "A slide-jump must NOT be modelled as an external-hyperlink relationship. If this assertion fails the library is confusing internal slide jumps with external URLs."
}
]
}
No rendered reference is available for this case.