Skip to content

Keep the markup that says which table style parts apply - #22

Merged
mantissaman merged 1 commit into
mainfrom
fix/table-style-conditional-formatting
Jul 29, 2026
Merged

Keep the markup that says which table style parts apply#22
mantissaman merged 1 commit into
mainfrom
fix/table-style-conditional-formatting

Conversation

@mantissaman

Copy link
Copy Markdown
Contributor

Addresses the table style symptom in #8, which I had previously been unable to reproduce.

Reproduced

Round-tripping a table styled the way Word writes one:

IN :  <w:tblLook w:val="04A0" w:firstRow="1" w:lastRow="0" w:firstColumn="1" w:lastColumn="0" w:noHBand="0" w:noVBand="1"/>
OUT:  <w:tblLook w:val="04A0"/>

IN :  <w:trPr><w:cnfStyle w:val="100000000000"/></w:trPr>
OUT:  gone entirely

w:tblStyle survived, which is why the earlier check looked clean and I reported the symptom as not reproducible. The style reference was never the problem. w:tblLook and w:cnfStyle are what say which conditional parts of that style to turn on: header row emphasis, row banding, first column formatting. Losing them leaves the style name in place and the table drawn with base formatting only, which is exactly what "the style of tables is not preserved" looks like from the outside.

Fixed

w:tblLook becomes a CT_TblLook carrying w:val alongside the six flags. Both forms are kept, because writers disagree about which to emit and readers disagree about which to trust, and OOXML booleans are accepted in both the 1/0 and true/false spellings.

w:cnfStyle was not modelled at all. It is now read and written on CT_TrPr and CT_TcPr, first in the element sequence as the schema requires.

One trap worth recording

Adding the field was not enough. Both types skip writing their properties when every field is unset, and those is_empty checks did not know about the new field. So a row or cell carrying only a cnfStyle was parsed correctly and then silently dropped again on the way out.

I only caught it because I re-ran the round trip after the change rather than trusting that parsing implied writing. There is a test for that specific case now.

Verified

The exact markup from the reproduction above now round-trips byte for byte. Three tests: the full conditional-formatting round trip, the properties-holding-only-cnfStyle case, and both boolean spellings.

Checks

cargo fmt --all --check, cargo clippy --workspace --all-targets -- -D warnings and the full suite all pass. 361 tests, up from 358.

python3 scripts/hash_harness.py --check passes with 28 entries matching. The generated samples do not use table styles with conditional formatting, so the baselines are untouched.

Note on #8

This is one of four symptoms in that issue. The TOC fields were fixed in #5, the vanishing tables in #9, and the front-page custom XML fields most likely by #9 as well although the reporter has not confirmed. So this is the last one I could act on without their file.

Breaking

CT_TblPr::look changes from Option<String> to Option<CT_TblLook>, and both CT_TrPr and CT_TcPr gain a field. It belongs in the same 0.4.0 as #20.

A load and save kept w:tblStyle but threw away the markup that says
which of that style's conditional parts to use, so a styled table came
back with its style name intact and drawn with base formatting only.
That reads as the style having been lost, which is what #8 reported.

Two things were dropped.

w:tblLook kept only w:val. Every attribute went missing, so firstRow,
lastRow, firstColumn, lastColumn, noHBand and noVBand were all lost.
It is now a CT_TblLook carrying w:val alongside the six flags. Both
forms are kept because writers disagree about which to emit and readers
disagree about which to trust, and OOXML booleans are accepted in the
1/0 and true/false spellings.

w:cnfStyle was not modelled at all and vanished from every row and
cell. It is now read and written on both CT_TrPr and CT_TcPr, first in
the element sequence as the schema requires.

Adding the field was not enough on its own. Both types skip writing
their properties when every field is unset, and those checks did not
know about the new field, so a row or cell carrying only a cnfStyle was
parsed and then silently dropped again on the way out. The emptiness
checks now include it, and a test covers exactly that case because it
is the kind of thing that looks fixed and is not.

Refs #8.
@mantissaman
mantissaman merged commit 0acc972 into main Jul 29, 2026
7 checks passed
@mantissaman
mantissaman deleted the fix/table-style-conditional-formatting branch July 29, 2026 22:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant