xlsx/unicode-bmp-round-trip

Cell A1 of the first worksheet carries a characteristic Unicode sample. The shared-strings table entry must contain the text verbatim at the XML infoset layer across every script range.

Cases (15)

Feature IDAxis bindingspython-xlsxxlsxjs
xlsx/unicode-bmp-round-trip--arabicscript=arabic
xlsx/unicode-bmp-round-trip--asciiscript=ascii
xlsx/unicode-bmp-round-trip--chinesescript=chinese
xlsx/unicode-bmp-round-trip--combiningscript=combining
xlsx/unicode-bmp-round-trip--cyrillicscript=cyrillic
xlsx/unicode-bmp-round-trip--devanagariscript=devanagari
xlsx/unicode-bmp-round-trip--emoji-bmpscript=emoji-bmp
xlsx/unicode-bmp-round-trip--emoji-smpscript=emoji-smp
xlsx/unicode-bmp-round-trip--greekscript=greek
xlsx/unicode-bmp-round-trip--hebrewscript=hebrew
xlsx/unicode-bmp-round-trip--japanesescript=japanese
xlsx/unicode-bmp-round-trip--koreanscript=korean
xlsx/unicode-bmp-round-trip--latin1script=latin1
xlsx/unicode-bmp-round-trip--thaiscript=thai
xlsx/unicode-bmp-round-trip--zwj-familyscript=zwj-family

Aggregate

LibraryPassFailPending
python-xlsx0015
xlsxjs0015

Parameter axes

Spec notes

SpreadsheetML string cells reference an entry in xl/sharedStrings.xml. The shared-strings entry is <si><t>...</t></si>. The text payload may appear as literal UTF-8 bytes or as numeric character references (&#NNNN;) — both forms are spec-legal and collapse to the same XML infoset. python-xlsx currently emits numeric character references for any non-ASCII code point (the library's XML serialiser defaults to ASCII-safe output); python-docx and python-pptx emit literal UTF-8. This difference is a readability / file-size regression but not a correctness bug: lxml reads both forms back identically, and the assertion below uses XPath contains() against the parsed text value. Any future change to emit literal UTF-8 in python-xlsx will satisfy the same assertion.

Generator source

scripts/gen_unicode_bmp_round_trip_xlsx.py — runs with --arg_template --script {script.id} --out fixtures/xlsx/unicode-bmp-round-trip--{script.id}.xlsx

#!/usr/bin/env python3
"""Generate ``fixtures/xlsx/unicode-bmp-round-trip--<script>.xlsx``.

Parameterised generator for the ``xlsx/unicode-bmp-round-trip`` family.
Writes a single-sheet workbook with cell A1 holding the payload for
one Unicode range. The manifest assertion checks that the
sharedStrings.xml <si>/<t> entry contains the sample substring.

Usage::

    python scripts/gen_unicode_bmp_round_trip_xlsx.py \\
        --script chinese \\
        --out fixtures/xlsx/unicode-bmp-round-trip--chinese.xlsx
"""

from __future__ import annotations

import argparse
import datetime as _dt
from pathlib import Path

from xlsx import Workbook

_REPO_ROOT = Path(__file__).resolve().parent.parent
_REPRODUCIBLE_DT = _dt.datetime(2000, 1, 1, 0, 0, 0)

_PAYLOADS: dict[str, str] = {
    "ascii":      "Hello world",
    "latin1":     "café naïve résumé",
    "cyrillic":   "Привет мир",
    "greek":      "Γειά σου κόσμε",
    "hebrew":     "שלום עולם",
    "arabic":     "مرحبا بالعالم",
    "chinese":    "你好世界",
    "japanese":   "こんにちは世界",
    "korean":     "안녕하세요 세계",
    "devanagari": "नमस्ते दुनिया",
    "thai":       "สวัสดีชาวโลก",
    "emoji-bmp":  "Star ✨ ok",
    "emoji-smp":  "Grin \U0001F600 ok",
    "combining":  "combined à decomposed à",
    "zwj-family": "family \U0001F468‍\U0001F469‍\U0001F466",
}


def _write(script: str, out: Path) -> None:
    if script not in _PAYLOADS:
        raise SystemExit(
            f"Unknown script id {script!r}; expected one of {sorted(_PAYLOADS)}"
        )
    wb = Workbook()
    ws = wb.active
    ws["A1"] = _PAYLOADS[script]
    out.parent.mkdir(parents=True, exist_ok=True)
    wb.save(out, zip_date_time=_REPRODUCIBLE_DT)


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--script", required=True)
    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.script, out_path)
    print(out_path)
    return 0


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

Manifest (parent, unexpanded)

{
  "$schema": "../manifest.schema.json",
  "id": "xlsx/unicode-bmp-round-trip",
  "kind": "parameterised",
  "title": "Unicode round-trip (xlsx)",
  "format": "xlsx",
  "category": "cell-data",
  "summary": "Cell A1 of the first worksheet carries a characteristic Unicode sample. The shared-strings table entry must contain the text verbatim at the XML infoset layer across every script range.",
  "spec": {
    "source": "ecma-376-5-part-1",
    "clause": "18.4.8",
    "element": "sst",
    "rnc_reference": "spec/ecma-376-5/part-1/rnc/SpreadsheetML.rnc",
    "xsd_reference": "spec/ecma-376-5/part-1/xsd/sml.xsd",
    "notes": "SpreadsheetML string cells reference an entry in xl/sharedStrings.xml. The shared-strings entry is <si><t>...</t></si>. The text payload may appear as literal UTF-8 bytes or as numeric character references (&#NNNN;) — both forms are spec-legal and collapse to the same XML infoset. python-xlsx currently emits numeric character references for any non-ASCII code point (the library's XML serialiser defaults to ASCII-safe output); python-docx and python-pptx emit literal UTF-8. This difference is a readability / file-size regression but not a correctness bug: lxml reads both forms back identically, and the assertion below uses XPath contains() against the parsed text value. Any future change to emit literal UTF-8 in python-xlsx will satisfy the same assertion."
  },
  "fixtures": {
    "machine": "xlsx/unicode-bmp-round-trip"
  },
  "generator": {
    "python": "scripts/gen_unicode_bmp_round_trip_xlsx.py",
    "arg_template": "--script {script.id} --out fixtures/xlsx/unicode-bmp-round-trip--{script.id}.xlsx"
  },
  "parameters": {
    "script": [
      {
        "id": "ascii",
        "sample": "Hello"
      },
      {
        "id": "latin1",
        "sample": "café"
      },
      {
        "id": "cyrillic",
        "sample": "Привет"
      },
      {
        "id": "greek",
        "sample": "Γειά"
      },
      {
        "id": "hebrew",
        "sample": "שלום"
      },
      {
        "id": "arabic",
        "sample": "مرحبا"
      },
      {
        "id": "chinese",
        "sample": "你好"
      },
      {
        "id": "japanese",
        "sample": "こんにちは"
      },
      {
        "id": "korean",
        "sample": "안녕하세요"
      },
      {
        "id": "devanagari",
        "sample": "नमस्ते"
      },
      {
        "id": "thai",
        "sample": "สวัสดี"
      },
      {
        "id": "emoji-bmp",
        "sample": "✨"
      },
      {
        "id": "emoji-smp",
        "sample": "😀"
      },
      {
        "id": "combining",
        "sample": "decomposed"
      },
      {
        "id": "zwj-family",
        "sample": "family"
      }
    ]
  },
  "assertions_template": [
    {
      "id": "shared-string-carries-sample-{script.id}",
      "part": "xl/sharedStrings.xml",
      "namespaces": {
        "x": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
      },
      "xpath": "//x:si/x:t[contains(., '{script.sample}')]",
      "must": "exist",
      "description": "The sharedStrings.xml entry must contain the characteristic sample substring for this script family at the XML infoset layer (independent of literal-UTF-8 vs. numeric-character-reference encoding on the wire)."
    }
  ]
}