fix: preserve text after <w:br/> by making CTR run-inner-content attributes collections - #10
Merged
Merged
Conversation
…ibutes collections Per shared-math.xsd CT_R lines 421-438, the choice has maxOccurs="unbounded", so every element it contains can repeat interleaved with the others. A math run like <m:r><m:t>x</m:t><w:br/><m:t>y</m:t></m:r> is schema-valid and Word-emitted: text on both sides of a break. The Omml model had CTR#t as a scalar attribute, so the second <m:t> overwrote the first on parse — silent data loss. Same for every other element in EGRunInnerContent and EGWordRunInnerContent that was declared without 'collection: true' (br, del_text, instr_text, del_instr_text, no_break_hyphen, object, pict, fld_char, ruby, footnote_reference, endnote_reference, comment_reference, drawing). Fix: - EGRunInnerContent: attribute :t, :ct_text, collection: true - EGWordRunInnerContent: every attribute gets collection: true (replaces the inconsistent mix of scalar and collection: 0..1) - CTR xml block: add 'ordered' declaration so the serializer emits children in parsed order, not grouped by source group. Without 'ordered', <m:t>x</m:t><w:br/><m:t>y</m:t> would serialize as <w:br/><m:t>x</m:t><m:t>y</m:t> — wrong order, breaks round-trip. Update existing specs that assumed scalar access (.t.content -> .t.first.content). Add new specs in wordprocessing_in_math_spec.rb verifying interleaved text+br round-trips without loss and that the serializer preserves document order. Resolves the plurimath 'Bug B' report: text after <w:br/> is no longer dropped.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the plurimath "Bug B" report: text after
<w:br/>is dropped on parse.Per
reference-docs/shared-math.xsdlines 421-438,CT_R's content model is:The choice has
maxOccurs="unbounded", so every element it contains can repeat, interleaved with the others. A math run like:is schema-valid and Word-emitted: text on both sides of a break.
The bug
CTR#twas declared as a scalar attribute (attribute :t, :ct_text, nocollection:), so parsing the above XML stored only onetvalue — the second overwrote the first. Same bug applied to every non-collection attribute inEGRunInnerContentandEGWordRunInnerContent:br,del_text,instr_text,del_instr_text,no_break_hyphen,object,pict,fld_char,ruby,footnote_reference,endnote_reference,comment_reference,drawing.The previous PR (#8) made
brparseable (viaCTWordprocessingEmpty/CTWordprocessingTextparallel types) but didn't catch that all these attributes needed to be collections for the unbounded choice to work correctly.The fix
EGRunInnerContent:attribute :t, :ct_text→attribute :t, :ct_text, collection: trueEGWordRunInnerContent: every attribute getscollection: true(replaces the inconsistent mix of scalar andcollection: 0..1)CTR: addordereddeclaration to the xml block so the serializer emits children in parsed document order, not grouped by source group. Withoutordered,<m:t>x</m:t><w:br/><m:t>y</m:t>would serialize as<w:br/><m:t>x</m:t><m:t>y</m:t>— wrong order, breaks round-trip fidelity and changes document semantics.Test plan
bundle exec rspec— 335 examples, 0 failures (was 333; +2 new interleaving tests)bundle exec rubocop— clean<m:r><m:t>x</m:t><w:br/><m:t>y</m:t></m:r>now parses withr.t.map(&:content) == ["x", "y"]andr.br.size == 1<m:t>x</m:t><w:br/><m:t>y</m:t>(not grouped).t.content→.t.first.content)New specs
spec/omml/wordprocessing_in_math_spec.rbadds a "multiple occurrences within one run" describe block:<w:br/>"<w:br/>interleaved with text"Impact for consumers
Breaking change for direct attribute access:
r.tnow returns an array, not a singleCTText. Consumers (Uniword, Plurimath) accessingr.t.contentneed to update tor.t.first.contentorr.t.map(&:content).This breaking change is necessary for schema correctness. The previous scalar form silently lost data on every multi-element math run — any document with text on both sides of a break, multiple breaks, or interleaved wordprocessing elements was corrupted on parse.