docx/rel-target-mode-external--mailto

An external hyperlink relationship must declare TargetMode="External" in word/_rels/document.xml.rels, and the Target URI must round-trip unchanged.

Library verdicts: python-docx: — docxjs: —

Metadata

Feature iddocx/rel-target-mode-external--mailto
Formatdocx
Categoryopc-packaging
Familydocx/rel-target-mode-external
Axis valueslink=mailto
Spececma-376-5-part-2 § 9.3 r:Relationship

XPath assertions

ID / partPredicateXPathpython-docxdocxjs
hyperlink-rel-exists-mailto
word/_rels/document.xml.rels
exist
The document-part rels file must declare a hyperlink relationship whose Target is the fixture URL.
//r:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink' and @Target='mailto:contact@example.com']
hyperlink-target-mode-external-mailto
word/_rels/document.xml.rels
equal = External
TargetMode on the external hyperlink rel must be the literal string 'External' (OPC §9.3).
//r:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink' and @Target='mailto:contact@example.com']/@TargetMode
hyperlink-target-uri-preserved-mailto
word/_rels/document.xml.rels
match = ^mailto:contact@example\.com$
The Target URI must round-trip byte-for-byte through the rels serialiser.
string(//r:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink' and @TargetMode='External']/@Target)

Render assertions

No render assertions declared.

Generator source

scripts/gen_rel_target_mode_external.py

#!/usr/bin/env python3
"""Generate ``fixtures/docx/rel-target-mode-external--<id>.docx`` fixtures.

Emits a one-paragraph document whose sole content is an external hyperlink
to ``--url`` displayed as ``--text``. python-docx routes this through
``Paragraph.add_hyperlink(url=..., style=None)`` which in turn calls
``part.relate_to(url, RT.HYPERLINK, is_external=True)`` — so the resulting
``word/_rels/document.xml.rels`` carries the hyperlink rel with
``TargetMode="External"``.

Manifest: ``features/docx/rel-target-mode-external.json``
"""

from __future__ import annotations

import argparse
from pathlib import Path

from docx import Document

_REPO_ROOT = Path(__file__).resolve().parent.parent


def _write(url: str, text: str, out: Path) -> None:
    doc = Document()
    paragraph = doc.add_paragraph()
    # style=None avoids the need for a built-in Hyperlink style to be present
    # in the template. The assertions only target the relationship file, so
    # the visible run's character style is immaterial.
    paragraph.add_hyperlink(url=url, text=text, style=None)
    out.parent.mkdir(parents=True, exist_ok=True)
    doc.save(out, reproducible=True)


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--url", required=True, help="External URI to embed as a hyperlink target")
    parser.add_argument("--text", required=True, help="Visible link text")
    parser.add_argument("--out", required=True, help="Output fixture path (repo-relative or absolute)")
    args = parser.parse_args()

    out_path = Path(args.out)
    if not out_path.is_absolute():
        out_path = _REPO_ROOT / out_path
    _write(args.url, args.text, out_path)
    print(out_path)
    return 0


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

Manifest (expanded)

{
  "$schema": "../manifest.schema.json",
  "id": "docx/rel-target-mode-external--mailto",
  "kind": "literal",
  "title": "External relationship target mode (docx)",
  "format": "docx",
  "category": "opc-packaging",
  "summary": "An external hyperlink relationship must declare TargetMode=\"External\" in word/_rels/document.xml.rels, and the Target URI must round-trip unchanged.",
  "spec": {
    "source": "ecma-376-5-part-2",
    "clause": "9.3",
    "element": "r:Relationship",
    "notes": "ECMA-376 Part 2 (OPC) §9.3 — the TargetMode attribute on a <Relationship> element is optional; when absent the implicit value is Internal. A relationship whose Target is a URI to a resource outside the package MUST carry TargetMode=\"External\" so readers do not attempt to resolve the target as a package-relative part. This family parameterises over three common URI schemes (https, http, mailto) that python-docx should all serialise through the external hyperlink rel type with TargetMode=\"External\"."
  },
  "fixtures": {
    "machine": "docx/rel-target-mode-external--mailto"
  },
  "generator": {
    "python": "scripts/gen_rel_target_mode_external.py",
    "arg_template": "--url \"{link.url}\" --text \"{link.text}\" --out fixtures/docx/rel-target-mode-external--{link.id}.docx"
  },
  "_expansion": {
    "parent_id": "docx/rel-target-mode-external",
    "bindings": {
      "link": "mailto"
    }
  },
  "assertions": [
    {
      "id": "hyperlink-rel-exists-mailto",
      "part": "word/_rels/document.xml.rels",
      "namespaces": {
        "r": "http://schemas.openxmlformats.org/package/2006/relationships"
      },
      "xpath": "//r:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink' and @Target='mailto:contact@example.com']",
      "must": "exist",
      "description": "The document-part rels file must declare a hyperlink relationship whose Target is the fixture URL."
    },
    {
      "id": "hyperlink-target-mode-external-mailto",
      "part": "word/_rels/document.xml.rels",
      "namespaces": {
        "r": "http://schemas.openxmlformats.org/package/2006/relationships"
      },
      "xpath": "//r:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink' and @Target='mailto:contact@example.com']/@TargetMode",
      "must": "equal",
      "value": "External",
      "description": "TargetMode on the external hyperlink rel must be the literal string 'External' (OPC §9.3)."
    },
    {
      "id": "hyperlink-target-uri-preserved-mailto",
      "part": "word/_rels/document.xml.rels",
      "namespaces": {
        "r": "http://schemas.openxmlformats.org/package/2006/relationships"
      },
      "xpath": "string(//r:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink' and @TargetMode='External']/@Target)",
      "must": "match",
      "value": "^mailto:contact@example\\.com$",
      "description": "The Target URI must round-trip byte-for-byte through the rels serialiser."
    }
  ]
}

Fixture

Download rel-target-mode-external--mailto.docx (18.6 KB)

Reference preview

No rendered reference is available for this case.

Spec notes

ECMA-376 Part 2 (OPC) §9.3 — the TargetMode attribute on a <Relationship> element is optional; when absent the implicit value is Internal. A relationship whose Target is a URI to a resource outside the package MUST carry TargetMode="External" so readers do not attempt to resolve the target as a package-relative part. This family parameterises over three common URI schemes (https, http, mailto) that python-docx should all serialise through the external hyperlink rel type with TargetMode="External".