From 2f103b3c76f2f2b72b8e497942ea77f71785c539 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Thu, 27 Aug 2026 14:51:13 -0700 Subject: [PATCH] Docx reader: handle case where non-header rows come before header rows. In this case we'll treat them all as the header in order to preserve the order. Added test case for #11833. --- pandoc.cabal | 1 + src/Text/Pandoc/Readers/Docx.hs | 16 +++++++++---- test/command/11833.docx | Bin 0 -> 10947 bytes test/command/11833.md | 40 ++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 test/command/11833.docx create mode 100644 test/command/11833.md diff --git a/pandoc.cabal b/pandoc.cabal index 65052f28f..565a22d5b 100644 --- a/pandoc.cabal +++ b/pandoc.cabal @@ -226,6 +226,7 @@ extra-source-files: test/command/9603.docx test/command/11113.docx test/command/11689.docx + test/command/11833.docx test/command/biblio.bib test/command/averroes.bib test/command/A.txt diff --git a/src/Text/Pandoc/Readers/Docx.hs b/src/Text/Pandoc/Readers/Docx.hs index 7c9271317..30e8a1bb2 100644 --- a/src/Text/Pandoc/Readers/Docx.hs +++ b/src/Text/Pandoc/Readers/Docx.hs @@ -629,14 +629,20 @@ rowsToRows rows = do return (fmap (Pandoc.Row nullAttr) cells) splitHeaderRows :: Bool -> [Docx.Row] -> ([Docx.Row], [Docx.Row]) -splitHeaderRows hasFirstRowFormatting rs = bimap reverse reverse $ fst - $ if hasFirstRowFormatting - then L.foldl' f ((take 1 rs, []), True) (drop 1 rs) - else L.foldl' f (([], []), False) rs +splitHeaderRows hasFirstRowFormatting rs = + bimap reverse reverse $ fst $ + if hasFirstRowFormatting + then L.foldl' f ((take 1 rs, []), True) (drop 1 rs) + else L.foldl' f (([], []), False) rs where f ((headerRows, bodyRows), previousRowWasHeader) r@(Docx.Row h cs) | h == HasTblHeader || (previousRowWasHeader && any isContinuationCell cs) - = ((r : headerRows, bodyRows), True) + = if null headerRows + -- in rare cases we have non-header rows before a header row. + -- in this case it's important to retain the order of rows, + -- so we promote the preceeding body rows to header rows: + then ((r : bodyRows, []), True) + else ((r : headerRows, bodyRows), True) | otherwise = ((headerRows, r : bodyRows), False) diff --git a/test/command/11833.docx b/test/command/11833.docx new file mode 100644 index 0000000000000000000000000000000000000000..8e97ef198ddd0cb7311ba67d9a674be152a89541 GIT binary patch literal 10947 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 + + + + + + + + +VENDOR SERVICE MODEL + + + + + +Question +Response +Comments +Evidence Reference + + + + +question1 +response1 +comment1 +evidence1 + + +question 2 +response 2 +comment 2 +evidence 2 + + + +```