Unwrap <p> inside <li> to prevent nested w:p in OOXML - #212
Open
blshkv wants to merge 4 commits into
Open
Conversation
When a list of one type was nested inside a list item of a different
type (e.g. <ul> inside <ol><li>, or <ol> inside <ul><li>), the nested
list items were silently dropped from the generated .docx output.
Two bugs caused this:
1. process_child_nodes in AST::List used XPath `./li/#{@list_tag}`,
which only promoted nested lists of the same type to sibling level.
A mixed-type nested list was never promoted, so its items remained
as children of a <w:p>, producing invalid OOXML that Word drops.
Fixed by changing the XPath to `./li/ul | ./li/ol`.
2. The allowed_children for ol and ul did not include the other list
type, so after promotion the structure validator raised:
"ol is not a valid child element of ul" (and vice versa).
Fixed by adding ul to ol's allowed_children and ol to ul's.
Fixes senny#197
Editors such as Trix wrap list item text in <p> tags, producing <li><p>text</p></li>. Since <li> already maps to a w:p paragraph node, nesting <p> (also w:p) inside it creates invalid OOXML that Word silently drops, losing the list item content. Fix by unwrapping <p> elements that are direct children of <li> in process_child_nodes before AST conversion, replacing each <p> with its own children — the same pre-processing that the mixed nested list fix already does for promoted list siblings.
This reverts commit 1b3733b.
Editors such as Trix wrap list item text in <p> tags, producing <li><p>text</p></li>. Since <li> already maps to a w:p paragraph node, nesting <p> (also w:p) inside it creates invalid OOXML that Word silently drops, losing the list item content entirely. Fix by unwrapping <p> elements that are direct children of <li> in process_child_nodes before AST conversion, replacing each <p> with its own children.
blshkv
added a commit
to blshkv/blshkv-overlay
that referenced
this pull request
May 24, 2026
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.
Problem
Editors such as Trix wrap list item text in
<p>tags, producing<li><p>text</p></li>. Since<li>already maps to aw:pparagraph node, the nested<p>(alsow:p) creates invalid OOXML that Word silently drops — the list item content is lost entirely.Root cause
process_child_nodesinAST::Listonly promoted nested list tags to sibling level. There was no preprocessing to unwrap<p>elements directly inside<li>before AST conversion, so the invalid nesting reached the OOXML output unchanged.Fix
Unwrap
<p>elements that are direct children of<li>inprocess_child_nodes, replacing each<p>with its own children before the AST is built.Change: 8 lines in
lib/sablon/html/ast.rb+ 1 regression test intest/html/ast_test.rb.