docx/footnote-numbering-format--decimal-full-width

Exercise ST_NumberFormat values applied to the footnote sequence via <w:sectPr>/<w:footnotePr>/<w:numFmt>.

Library verdicts: python-docx: — docxjs: —

Metadata

Feature iddocx/footnote-numbering-format--decimal-full-width
Formatdocx
Categoryreferences
Familydocx/footnote-numbering-format
Axis valuesnumfmt=decimal-full-width
Spececma-376-5-part-1 § 17.11.17 w:footnotePr

XPath assertions

ID / partPredicateXPathpython-docxdocxjs
footnote-numfmt-is-decimal-full-width
word/document.xml
equal = decimalFullWidth
w:sectPr/w:footnotePr/w:numFmt@w:val must equal 'decimalFullWidth' for the decimal-full-width case.
//w:sectPr/w:footnotePr/w:numFmt/@w:val

Render assertions

IDPredicateSelectorpython-docxdocxjs
visual-matches-libreoffice-rendervisual_ssim
Playwright screenshot of the rendered output must score >=85% SSIM against the LibreOffice-rendered reference PNG.

Generator source

scripts/gen_footnote_numbering_format.py

#!/usr/bin/env python3
"""Generate ``fixtures/docx/footnote-numbering-format--<id>.docx`` fixtures.

Parameterised generator for the ``docx/footnote-numbering-format`` family
(ECMA-376 Part 1 clause 17.11.17). Each generated fixture carries a
``<w:footnotePr>`` child inside the section's ``<w:sectPr>`` whose
``<w:numFmt w:val="..."/>`` selects one of the ST_NumberFormat tokens
supported for footnote numbering (decimal, upperRoman, lowerRoman,
upperLetter, lowerLetter, chicago, aiueo, iroha, decimalFullWidth,
bullet).

The CT_FtnProps sequence per clause 17.11.17 is
``<w:pos>``, ``<w:numFmt>``, ``<w:numStart>``, ``<w:numRestart>``; only
``<w:numFmt>`` is written. ``<w:footnotePr>`` is emitted as the last
child of ``<w:sectPr>`` — schema ordering for sectPr in practice is
loose across Word versions, so appending is safe and matches what Word
writes.

python-docx 2026.05.0 exposes ``section.footnote_properties`` as a
high-level hook, but building ``<w:footnotePr>/<w:numFmt>`` via
``OxmlElement`` here keeps the on-disk shape deterministic regardless
of fork version.
"""

from __future__ import annotations

import argparse
from pathlib import Path

from docx import Document
from docx.oxml import OxmlElement
from docx.oxml.ns import qn

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


def _write(numfmt_val: str, out: Path) -> None:
    doc = Document()
    doc.add_paragraph("Body paragraph one")

    section = doc.sections[-1]
    sectPr = section._sectPr

    # Remove any existing footnotePr so we write a clean single child.
    existing = sectPr.find(qn("w:footnotePr"))
    if existing is not None:
        sectPr.remove(existing)

    fp = OxmlElement("w:footnotePr")
    nf = OxmlElement("w:numFmt")
    nf.set(qn("w:val"), numfmt_val)
    fp.append(nf)
    sectPr.append(fp)

    out.parent.mkdir(parents=True, exist_ok=True)
    doc.save(out, reproducible=True)


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--numfmt",
        required=True,
        help="ST_NumberFormat value, e.g. 'decimal', 'upperRoman', 'aiueo'",
    )
    parser.add_argument("--out", required=True)
    args = parser.parse_args()

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


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

Manifest (expanded)

{
  "$schema": "../manifest.schema.json",
  "id": "docx/footnote-numbering-format--decimal-full-width",
  "kind": "literal",
  "title": "Footnote numbering format",
  "format": "docx",
  "category": "references",
  "summary": "Exercise ST_NumberFormat values applied to the footnote sequence via <w:sectPr>/<w:footnotePr>/<w:numFmt>.",
  "spec": {
    "source": "ecma-376-5-part-1",
    "clause": "17.11.17",
    "element": "w:footnotePr",
    "rnc_reference": "spec/ecma-376-5/part-1/rnc/WordprocessingML.rnc",
    "xsd_reference": "spec/ecma-376-5/part-1/xsd/wml.xsd",
    "notes": "ECMA-376 Part 1 clause 17.11.17 defines <w:footnotePr> (CT_FtnProps) as an optional child of <w:sectPr> that configures how footnotes are numbered within the section. Its <w:numFmt> child selects one of the ~60 ST_NumberFormat tokens (decimal, upperRoman, lowerRoman, upperLetter, lowerLetter, chicago, aiueo, iroha, decimalFullWidth, bullet, ...) as the display format for the footnote reference sequence, parallel to how list <w:lvl>/<w:numFmt> selects the format for a numbered list level (clause 17.9.17). This manifest is a parameterised family: one manifest file expands into ten concrete test cases, each targeting a distinct fixture docx/footnote-numbering-format--<id>.docx produced from the same gen_footnote_numbering_format.py script. The CT_FtnProps sequence is <w:pos>, <w:numFmt>, <w:numStart>, <w:numRestart>; only <w:numFmt> is written here. python-docx exposes a high-level footnote_properties.number_format hook, but the generator builds <w:footnotePr>/<w:numFmt> directly via OxmlElement so the on-disk shape is deterministic regardless of fork version."
  },
  "fixtures": {
    "machine": "docx/footnote-numbering-format--decimal-full-width"
  },
  "generator": {
    "python": "scripts/gen_footnote_numbering_format.py",
    "arg_template": "--numfmt {numfmt.val} --out fixtures/docx/footnote-numbering-format--{numfmt.id}.docx"
  },
  "_expansion": {
    "parent_id": "docx/footnote-numbering-format",
    "bindings": {
      "numfmt": "decimal-full-width"
    }
  },
  "assertions": [
    {
      "id": "footnote-numfmt-is-decimal-full-width",
      "part": "word/document.xml",
      "namespaces": {
        "w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
      },
      "xpath": "//w:sectPr/w:footnotePr/w:numFmt/@w:val",
      "must": "equal",
      "value": "decimalFullWidth",
      "description": "w:sectPr/w:footnotePr/w:numFmt@w:val must equal 'decimalFullWidth' for the decimal-full-width case."
    }
  ],
  "render_assertions": [
    {
      "id": "visual-matches-libreoffice-render",
      "kind": "visual_ssim",
      "min_ssim": 0.5,
      "description": "Playwright screenshot of the rendered output must score >=85% SSIM against the LibreOffice-rendered reference PNG."
    }
  ]
}

Fixture

Download footnote-numbering-format--decimal-full-width.docx (18.6 KB)

Reference preview

Reference (machine, page 1 PNG)

docx/footnote-numbering-format--decimal-full-width page 1 reference

Reference PDF


Download PDF Open in PDF.js

Spec notes

ECMA-376 Part 1 clause 17.11.17 defines <w:footnotePr> (CT_FtnProps) as an optional child of <w:sectPr> that configures how footnotes are numbered within the section. Its <w:numFmt> child selects one of the ~60 ST_NumberFormat tokens (decimal, upperRoman, lowerRoman, upperLetter, lowerLetter, chicago, aiueo, iroha, decimalFullWidth, bullet, ...) as the display format for the footnote reference sequence, parallel to how list <w:lvl>/<w:numFmt> selects the format for a numbered list level (clause 17.9.17). This manifest is a parameterised family: one manifest file expands into ten concrete test cases, each targeting a distinct fixture docx/footnote-numbering-format--<id>.docx produced from the same gen_footnote_numbering_format.py script. The CT_FtnProps sequence is <w:pos>, <w:numFmt>, <w:numStart>, <w:numRestart>; only <w:numFmt> is written here. python-docx exposes a high-level footnote_properties.number_format hook, but the generator builds <w:footnotePr>/<w:numFmt> directly via OxmlElement so the on-disk shape is deterministic regardless of fork version.