xlsx/mc-ignorable-ext

Pin Excel's Markup-Compatibility shape for post-2010 spreadsheet features: the worksheet root declares the x14ac + x14r prefixes and lists them in mc:Ignorable; an x14 sparklineGroup extension lives inside <extLst><ext uri="{05C60535-1F16-4fd2-B633-F4F36F0B64E0}">, which is the Microsoft-allocated GUID for the sparkline extension.

Library verdicts: python-xlsx: — xlsxjs: —

Metadata

Feature idxlsx/mc-ignorable-ext
Formatxlsx
Categorymarkup-compatibility
Spececma-376-5-part-3 § 10 mc:Ignorable

XPath assertions

ID / partPredicateXPathpython-xlsxxlsxjs
mc-ignorable-present
xl/worksheets/sheet1.xml
exist
The <worksheet> root must carry an mc:Ignorable attribute.
/s:worksheet/@mc:Ignorable
mc-ignorable-lists-x14ac
xl/worksheets/sheet1.xml
match = (^|\s)x14ac(\s|$)
The x14ac prefix (Excel 2010 Ac extension) must appear as a whitespace-separated token in mc:Ignorable.
/s:worksheet/@mc:Ignorable
mc-ignorable-lists-x14r
xl/worksheets/sheet1.xml
match = (^|\s)x14r(\s|$)
The x14r prefix (Excel 2013 Revisions) must appear as a whitespace-separated token in mc:Ignorable.
/s:worksheet/@mc:Ignorable
worksheet-namespace-x14ac-declared
xl/worksheets/sheet1.xml
equal = http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac
The x14ac prefix on <worksheet> must be bound to the Excel 2010 Ac-extension namespace URI.
string(/s:worksheet/namespace::*[name()='x14ac'])
worksheet-namespace-x14r-declared
xl/worksheets/sheet1.xml
equal = http://schemas.microsoft.com/office/spreadsheetml/2009/9/main/revisions
The x14r prefix on <worksheet> must be bound to the Excel 2013 revisions namespace URI.
string(/s:worksheet/namespace::*[name()='x14r'])
sparkline-ext-uri
xl/worksheets/sheet1.xml
equal = {05C60535-1F16-4fd2-B633-F4F36F0B64E0}
The <ext> wrapping sparkline content must carry Microsoft's sparkline GUID.
//s:extLst/s:ext/@uri
sparkline-group-present
xl/worksheets/sheet1.xml
exist
The sparkline payload under <ext> must carry at least one <x14:sparklineGroup>.
//s:extLst/s:ext/x14:sparklineGroups/x14:sparklineGroup
sparkline-formula
xl/worksheets/sheet1.xml
equal = Sheet!A1:G1
The sparkline's source formula must point at the 7-cell trend range.
string(//x14:sparkline/xm:f)
sparkline-target-cell
xl/worksheets/sheet1.xml
equal = A3
The sparkline must render into the expected cell (A3).
string(//x14:sparkline/xm:sqref)

Render assertions

No render assertions declared.

Generator source

scripts/gen_xlsx_mc_ignorable_ext.py

#!/usr/bin/env python3
"""Generate ``fixtures/xlsx/mc-ignorable-ext.xlsx``.

A minimal workbook with one sparkline, used to pin the
Markup-Compatibility shape Excel 2010+ writes: a ``<worksheet>`` root
that carries ``xmlns:x14ac`` / ``xmlns:x14r`` namespace declarations
plus ``mc:Ignorable="x14ac x14r"``, and an ``<extLst>/<ext uri="{GUID}">``
wrapping an ``<x14:sparklineGroups>`` payload under the x14 namespace.

python-xlsx emits the sparkline payload but does not declare the Excel
2010-Ac-extension or Excel 2013-Row-Runtime prefixes on the sheet root
and does not populate ``mc:Ignorable``. This generator patches the
saved sheet XML to add the missing namespace declarations and
mc:Ignorable value — matching Office's own output — so that the corpus
assertion has a stable target. A future python-xlsx change that brings
native mc:Ignorable support can drop the patch step.
"""

from __future__ import annotations

import datetime as _dt
import io
import zipfile
from pathlib import Path

from lxml import etree
from xlsx import Workbook

_REPO_ROOT = Path(__file__).resolve().parent.parent
_OUT = _REPO_ROOT / "fixtures" / "xlsx" / "mc-ignorable-ext.xlsx"
_REPRODUCIBLE_DT = _dt.datetime(2000, 1, 1, 0, 0, 0)

_S_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
_MC_NS = "http://schemas.openxmlformats.org/markup-compatibility/2006"
_X14AC_NS = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac"
_X14R_NS = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main/revisions"


def _rewrite_sheet(xml: bytes) -> bytes:
    """Rewrite the sheet XML root to declare x14ac + x14r and mc:Ignorable.

    Rebuilds the root element with an augmented nsmap, copies children
    and attributes across verbatim, then sets ``mc:Ignorable`` so
    downstream readers know they can skip x14ac-only / x14r-only
    extensions without bailing out.
    """
    tree = etree.fromstring(xml)
    nsmap = {
        None:    _S_NS,
        "mc":    _MC_NS,
        "x14ac": _X14AC_NS,
        "x14r":  _X14R_NS,
    }
    new_root = etree.Element(f"{{{_S_NS}}}worksheet", nsmap=nsmap)
    # Preserve xml:space and any other attributes.
    for k, v in tree.attrib.items():
        new_root.set(k, v)
    new_root.set(f"{{{_MC_NS}}}Ignorable", "x14ac x14r")
    for child in list(tree):
        new_root.append(child)
    return etree.tostring(
        new_root, xml_declaration=True, encoding="UTF-8", standalone=True
    )


def _repack(src: bytes, patched_sheet_xml: bytes) -> bytes:
    out = io.BytesIO()
    with zipfile.ZipFile(io.BytesIO(src)) as zin, zipfile.ZipFile(
        out, "w", zipfile.ZIP_DEFLATED
    ) as zout:
        for info in zin.infolist():
            data = (
                patched_sheet_xml
                if info.filename == "xl/worksheets/sheet1.xml"
                else zin.read(info.filename)
            )
            new_info = zipfile.ZipInfo(filename=info.filename, date_time=info.date_time)
            new_info.compress_type = info.compress_type
            zout.writestr(new_info, data)
    return out.getvalue()


def main() -> int:
    wb = Workbook()
    ws = wb.active
    # 7-point trend series in row 1.
    for col, value in enumerate([3, 7, 4, 9, 5, 8, 6], start=1):
        ws.cell(row=1, column=col, value=value)
    # Sparkline over the series, rendered into cell A3.
    ws.add_sparkline(location="A3", data="Sheet!A1:G1", type="line")
    buf = io.BytesIO()
    wb.save(buf, zip_date_time=_REPRODUCIBLE_DT)
    with zipfile.ZipFile(io.BytesIO(buf.getvalue())) as zf:
        sheet_xml = zf.read("xl/worksheets/sheet1.xml")
    patched = _repack(buf.getvalue(), _rewrite_sheet(sheet_xml))
    _OUT.parent.mkdir(parents=True, exist_ok=True)
    _OUT.write_bytes(patched)
    print(_OUT)
    return 0


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

Manifest (expanded)

{
  "$schema": "../manifest.schema.json",
  "id": "xlsx/mc-ignorable-ext",
  "title": "Markup Compatibility: mc:Ignorable + x14 sparkline extLst",
  "format": "xlsx",
  "category": "markup-compatibility",
  "summary": "Pin Excel's Markup-Compatibility shape for post-2010 spreadsheet features: the worksheet root declares the x14ac + x14r prefixes and lists them in mc:Ignorable; an x14 sparklineGroup extension lives inside <extLst><ext uri=\"{05C60535-1F16-4fd2-B633-F4F36F0B64E0}\">, which is the Microsoft-allocated GUID for the sparkline extension.",
  "spec": {
    "source": "ecma-376-5-part-3",
    "clause": "10",
    "element": "mc:Ignorable",
    "notes": "ECMA-376 Part 3 §10.1.1 defines mc:Ignorable. In SpreadsheetML, Excel 2010 introduced sparklines, table styles' theme colors, and several other features in the x14 namespace (http://schemas.microsoft.com/office/spreadsheetml/2009/9/main) and attributes like x14ac:dyDescent under x14ac (http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac). Excel 2013+ added x14r (revisions). The convention is: producers declare xmlns:x14ac and xmlns:x14r on the <worksheet> root and list both prefixes in mc:Ignorable so a pre-2010 reader can skip x14ac attributes and x14r elements without error. The sparkline payload itself lives under <extLst>/<ext uri=\"{05C60535-1F16-4fd2-B633-F4F36F0B64E0}\"> — that GUID is Microsoft's registered identifier for the sparkline extension. This fixture pins both sides of that convention."
  },
  "fixtures": {
    "machine": "xlsx/mc-ignorable-ext"
  },
  "generator": {
    "python": "scripts/gen_xlsx_mc_ignorable_ext.py"
  },
  "assertions": [
    {
      "id": "mc-ignorable-present",
      "part": "xl/worksheets/sheet1.xml",
      "namespaces": {
        "s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
        "mc": "http://schemas.openxmlformats.org/markup-compatibility/2006"
      },
      "xpath": "/s:worksheet/@mc:Ignorable",
      "must": "exist",
      "description": "The <worksheet> root must carry an mc:Ignorable attribute."
    },
    {
      "id": "mc-ignorable-lists-x14ac",
      "part": "xl/worksheets/sheet1.xml",
      "namespaces": {
        "s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
        "mc": "http://schemas.openxmlformats.org/markup-compatibility/2006"
      },
      "xpath": "/s:worksheet/@mc:Ignorable",
      "must": "match",
      "value": "(^|\\s)x14ac(\\s|$)",
      "description": "The x14ac prefix (Excel 2010 Ac extension) must appear as a whitespace-separated token in mc:Ignorable."
    },
    {
      "id": "mc-ignorable-lists-x14r",
      "part": "xl/worksheets/sheet1.xml",
      "namespaces": {
        "s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
        "mc": "http://schemas.openxmlformats.org/markup-compatibility/2006"
      },
      "xpath": "/s:worksheet/@mc:Ignorable",
      "must": "match",
      "value": "(^|\\s)x14r(\\s|$)",
      "description": "The x14r prefix (Excel 2013 Revisions) must appear as a whitespace-separated token in mc:Ignorable."
    },
    {
      "id": "worksheet-namespace-x14ac-declared",
      "part": "xl/worksheets/sheet1.xml",
      "namespaces": {
        "s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
      },
      "xpath": "string(/s:worksheet/namespace::*[name()='x14ac'])",
      "must": "equal",
      "value": "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac",
      "description": "The x14ac prefix on <worksheet> must be bound to the Excel 2010 Ac-extension namespace URI."
    },
    {
      "id": "worksheet-namespace-x14r-declared",
      "part": "xl/worksheets/sheet1.xml",
      "namespaces": {
        "s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
      },
      "xpath": "string(/s:worksheet/namespace::*[name()='x14r'])",
      "must": "equal",
      "value": "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main/revisions",
      "description": "The x14r prefix on <worksheet> must be bound to the Excel 2013 revisions namespace URI."
    },
    {
      "id": "sparkline-ext-uri",
      "part": "xl/worksheets/sheet1.xml",
      "namespaces": {
        "s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
      },
      "xpath": "//s:extLst/s:ext/@uri",
      "must": "equal",
      "value": "{05C60535-1F16-4fd2-B633-F4F36F0B64E0}",
      "description": "The <ext> wrapping sparkline content must carry Microsoft's sparkline GUID."
    },
    {
      "id": "sparkline-group-present",
      "part": "xl/worksheets/sheet1.xml",
      "namespaces": {
        "s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
        "x14": "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
      },
      "xpath": "//s:extLst/s:ext/x14:sparklineGroups/x14:sparklineGroup",
      "must": "exist",
      "description": "The sparkline payload under <ext> must carry at least one <x14:sparklineGroup>."
    },
    {
      "id": "sparkline-formula",
      "part": "xl/worksheets/sheet1.xml",
      "namespaces": {
        "s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
        "x14": "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main",
        "xm": "http://schemas.microsoft.com/office/excel/2006/main"
      },
      "xpath": "string(//x14:sparkline/xm:f)",
      "must": "equal",
      "value": "Sheet!A1:G1",
      "description": "The sparkline's source formula must point at the 7-cell trend range."
    },
    {
      "id": "sparkline-target-cell",
      "part": "xl/worksheets/sheet1.xml",
      "namespaces": {
        "s": "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
        "x14": "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main",
        "xm": "http://schemas.microsoft.com/office/excel/2006/main"
      },
      "xpath": "string(//x14:sparkline/xm:sqref)",
      "must": "equal",
      "value": "A3",
      "description": "The sparkline must render into the expected cell (A3)."
    }
  ]
}

Fixture

Download mc-ignorable-ext.xlsx (5.0 KB)

Reference preview

No rendered reference is available for this case.

Spec notes

ECMA-376 Part 3 §10.1.1 defines mc:Ignorable. In SpreadsheetML, Excel 2010 introduced sparklines, table styles' theme colors, and several other features in the x14 namespace (http://schemas.microsoft.com/office/spreadsheetml/2009/9/main) and attributes like x14ac:dyDescent under x14ac (http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac). Excel 2013+ added x14r (revisions). The convention is: producers declare xmlns:x14ac and xmlns:x14r on the <worksheet> root and list both prefixes in mc:Ignorable so a pre-2010 reader can skip x14ac attributes and x14r elements without error. The sparkline payload itself lives under <extLst>/<ext uri="{05C60535-1F16-4fd2-B633-F4F36F0B64E0}"> — that GUID is Microsoft's registered identifier for the sparkline extension. This fixture pins both sides of that convention.