xlsx/preserve-comment-rich-text

Excel writes comments as a sequence of formatted runs <r><rPr>…</rPr><t>…</t></r>: a bold author prefix followed by the plain body is the default shape. python-xlsx collapses the entire <text> to a single <t> on save, dropping every per-run format (bold, font, size, color). This manifest pins that gap as a conformance failure.

Library verdicts: python-xlsx: — xlsxjs: —

Metadata

Feature idxlsx/preserve-comment-rich-text
Formatxlsx
Categoryround-trip
Spececma-376-5-part-1 § 18.7.5 comment

XPath assertions

ID / partPredicateXPathpython-xlsxxlsxjs
comment-run-preserved
xl/comments1.xml
exist
At least one <r> child must survive inside a comment's <text>. python-xlsx currently collapses rich text to a single <t>, stripping every <r>.
//x:comments/x:commentList/x:comment/x:text/x:r
comment-run-properties-preserved
xl/comments1.xml
exist
At least one run-property block <rPr> must survive. Without it the visual distinction between the bold author prefix and the plain body is lost.
//x:comments/x:commentList/x:comment/x:text/x:r/x:rPr
comment-bold-prefix-preserved
xl/comments1.xml
exist
At least one <b/> must survive inside a run-property block — comment 'Author:' prefixes are bold by convention.
//x:comments/x:commentList/x:comment/x:text/x:r/x:rPr/x:b

Render assertions

No render assertions declared.

Manifest (expanded)

{
  "$schema": "../manifest.schema.json",
  "id": "xlsx/preserve-comment-rich-text",
  "title": "Preserve comment rich-text runs across round-trip",
  "format": "xlsx",
  "category": "round-trip",
  "summary": "Excel writes comments as a sequence of formatted runs <r><rPr>…</rPr><t>…</t></r>: a bold author prefix followed by the plain body is the default shape. python-xlsx collapses the entire <text> to a single <t> on save, dropping every per-run format (bold, font, size, color). This manifest pins that gap as a conformance failure.",
  "roles": [
    "authoring"
  ],
  "spec": {
    "source": "ecma-376-5-part-1",
    "clause": "18.7.5",
    "element": "comment",
    "rnc_reference": "spec/ecma-376-5/part-1/rnc/SpreadsheetML.rnc",
    "xsd_reference": "spec/ecma-376-5/part-1/xsd/sml.xsd",
    "notes": "ECMA-376 Part 1 clause 18.7 specifies xl/comments*.xml and its <commentList>/<comment>/<text> structure. The <text> child uses the same CT_Rst shape as <si> in sharedStrings.xml — so rich-text runs <r><rPr>…</rPr><t>…</t></r> are schema-legal and, in practice, Excel emits them unconditionally (the default 'author:' prefix is bold, the body is plain). Code: src/xlsx/comments/comments.py — Comment.__init__ stores only self.content as str; src/xlsx/comments/comment_sheet.py::CommentRecord.from_cell replays it as self.text.t (a single <t> child). python-xlsx has CellRichText / InlineFont support for inline strings but the comment path never uses it."
  },
  "fixtures": {
    "machine": "xlsx/preserve-comment-rich-text"
  },
  "round_trip": {
    "library": "python-xlsx",
    "source_fixture": "xlsx/preserve-comment-rich-text",
    "notes": "Source is a copy of python-xlsx's own bundled comments.xlsx test fixture, authored in Excel with the standard 'bold author prefix + plain body' comment shape. Runner loads it, saves through python-xlsx, and evaluates the assertions against the re-saved bytes."
  },
  "assertions": [
    {
      "id": "comment-run-preserved",
      "part": "xl/comments1.xml",
      "namespaces": {
        "x": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
      },
      "xpath": "//x:comments/x:commentList/x:comment/x:text/x:r",
      "must": "exist",
      "description": "At least one <r> child must survive inside a comment's <text>. python-xlsx currently collapses rich text to a single <t>, stripping every <r>."
    },
    {
      "id": "comment-run-properties-preserved",
      "part": "xl/comments1.xml",
      "namespaces": {
        "x": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
      },
      "xpath": "//x:comments/x:commentList/x:comment/x:text/x:r/x:rPr",
      "must": "exist",
      "description": "At least one run-property block <rPr> must survive. Without it the visual distinction between the bold author prefix and the plain body is lost."
    },
    {
      "id": "comment-bold-prefix-preserved",
      "part": "xl/comments1.xml",
      "namespaces": {
        "x": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
      },
      "xpath": "//x:comments/x:commentList/x:comment/x:text/x:r/x:rPr/x:b",
      "must": "exist",
      "description": "At least one <b/> must survive inside a run-property block — comment 'Author:' prefixes are bold by convention."
    }
  ]
}

Fixture

Download preserve-comment-rich-text.xlsx (12.9 KB)

Reference preview

No rendered reference is available for this case.

Spec notes

ECMA-376 Part 1 clause 18.7 specifies xl/comments*.xml and its <commentList>/<comment>/<text> structure. The <text> child uses the same CT_Rst shape as <si> in sharedStrings.xml — so rich-text runs <r><rPr>…</rPr><t>…</t></r> are schema-legal and, in practice, Excel emits them unconditionally (the default 'author:' prefix is bold, the body is plain). Code: src/xlsx/comments/comments.py — Comment.__init__ stores only self.content as str; src/xlsx/comments/comment_sheet.py::CommentRecord.from_cell replays it as self.text.t (a single <t> child). python-xlsx has CellRichText / InlineFont support for inline strings but the comment path never uses it.