From 79806fa54aba8e4d513bf82c3507384bf0d0c933 Mon Sep 17 00:00:00 2001 From: Lowell Stewart Date: Sat, 3 Jan 2026 16:58:13 -0700 Subject: [PATCH 1/3] fix bug where conditionals can leave a table cell in an invalid state, causing Word to report an error. --- .../DocumentAssemblerTests.cs | 1 + .../DocumentAssembler/DocumentAssembler.cs | 8 +++++++- .../DA268-Block-Conditional-In-Table-Cell.docx | Bin 0 -> 19774 bytes TestFiles/DA268-data.xml | 4 ++++ 4 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 TestFiles/DA268-Block-Conditional-In-Table-Cell.docx create mode 100644 TestFiles/DA268-data.xml diff --git a/OpenXmlPowerTools.Tests/DocumentAssemblerTests.cs b/OpenXmlPowerTools.Tests/DocumentAssemblerTests.cs index cdbdb3bb..c775eadc 100644 --- a/OpenXmlPowerTools.Tests/DocumentAssemblerTests.cs +++ b/OpenXmlPowerTools.Tests/DocumentAssemblerTests.cs @@ -107,6 +107,7 @@ public class DaTests [InlineData("DA264-InvalidRunLevelRepeat.docx", "DA-Data.xml", true)] [InlineData("DA265-RunLevelRepeatWithWhiteSpaceBefore.docx", "DA-Data.xml", false)] [InlineData("DA266-RunLevelRepeat-NoData.docx", "DA-Data.xml", true)] + [InlineData("DA268-Block-Conditional-In-Table-Cell.docx", "DA268-data.xml", false)] public void DA101(string name, string data, bool err) { var sourceDir = new DirectoryInfo("../../../../TestFiles/"); diff --git a/OpenXmlPowerTools/DocumentAssembler/DocumentAssembler.cs b/OpenXmlPowerTools/DocumentAssembler/DocumentAssembler.cs index a639ce5d..f3d18a07 100644 --- a/OpenXmlPowerTools/DocumentAssembler/DocumentAssembler.cs +++ b/OpenXmlPowerTools/DocumentAssembler/DocumentAssembler.cs @@ -873,9 +873,15 @@ private class RunReplacementInfo } return null; } + var transformedNodes = element.Nodes().Select(n => ContentReplacementTransform(n, data, templateError, owningPart)); + if (element.Name == W.tc && transformedNodes.All(n => n == null || (n is XElement && (n as XElement).Name == W.tcPr))) + { + // avoid empty table cells, which are invalid -- add an empty paragraph back in + transformedNodes = transformedNodes.Concat(new XNode[] { new XElement(W.p) }); + } return new XElement(element.Name, element.Attributes(), - element.Nodes().Select(n => ContentReplacementTransform(n, data, templateError, owningPart))); + transformedNodes); } return node; } diff --git a/TestFiles/DA268-Block-Conditional-In-Table-Cell.docx b/TestFiles/DA268-Block-Conditional-In-Table-Cell.docx new file mode 100644 index 0000000000000000000000000000000000000000..7796dabba23e5bf0afba1f271a46f5e9a21f5457 GIT binary patch literal 19774 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 UXxl$MI0PUsP#~aEk)KEZ4>ii;=l}o! literal 0 HcmV?d00001 diff --git a/TestFiles/DA268-data.xml b/TestFiles/DA268-data.xml new file mode 100644 index 00000000..10750a67 --- /dev/null +++ b/TestFiles/DA268-data.xml @@ -0,0 +1,4 @@ + + + False + \ No newline at end of file From f3f820f800dbd1b9f31577671233f5d18acdd4f9 Mon Sep 17 00:00:00 2001 From: Lowell Stewart Date: Wed, 21 Jan 2026 17:02:31 -0700 Subject: [PATCH 2/3] more comprehensive fix for DA268 (commit 6811ec2ca4c1878a42fb4feb8f402111a13a1f59) --- .../DocumentAssembler/DocumentAssembler.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/OpenXmlPowerTools/DocumentAssembler/DocumentAssembler.cs b/OpenXmlPowerTools/DocumentAssembler/DocumentAssembler.cs index f3d18a07..0d47c875 100644 --- a/OpenXmlPowerTools/DocumentAssembler/DocumentAssembler.cs +++ b/OpenXmlPowerTools/DocumentAssembler/DocumentAssembler.cs @@ -873,11 +873,18 @@ private class RunReplacementInfo } return null; } - var transformedNodes = element.Nodes().Select(n => ContentReplacementTransform(n, data, templateError, owningPart)); - if (element.Name == W.tc && transformedNodes.All(n => n == null || (n is XElement && (n as XElement).Name == W.tcPr))) + var transformedNodes = element.Nodes().Select(n => ContentReplacementTransform(n, data, asmResult, owningPart)); + if (element.Name == W.tc) { - // avoid empty table cells, which are invalid -- add an empty paragraph back in - transformedNodes = transformedNodes.Concat(new XNode[] { new XElement(W.p) }); + // Check if the table cell contains any paragraph elements + var nodesList = transformedNodes.ToList(); + var hasParagraph = nodesList.Any(n => n is XElement xe && xe.Name == W.p); + if (!hasParagraph) + { + // avoid empty table cells, which are invalid -- add an empty paragraph back in + nodesList.Add(new XElement(W.p)); + } + transformedNodes = nodesList; } return new XElement(element.Name, element.Attributes(), From db482af095f80713ccac864d756aa3d23e9993d6 Mon Sep 17 00:00:00 2001 From: Lowell Stewart Date: Wed, 21 Jan 2026 17:33:20 -0700 Subject: [PATCH 3/3] only add paragraph when no other block-level elements exist in the table cell --- .../DocumentAssembler/DocumentAssembler.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/OpenXmlPowerTools/DocumentAssembler/DocumentAssembler.cs b/OpenXmlPowerTools/DocumentAssembler/DocumentAssembler.cs index 0d47c875..478aad91 100644 --- a/OpenXmlPowerTools/DocumentAssembler/DocumentAssembler.cs +++ b/OpenXmlPowerTools/DocumentAssembler/DocumentAssembler.cs @@ -873,15 +873,17 @@ private class RunReplacementInfo } return null; } - var transformedNodes = element.Nodes().Select(n => ContentReplacementTransform(n, data, asmResult, owningPart)); + var transformedNodes = element.Nodes().Select(n => ContentReplacementTransform(n, data, templateError, owningPart)); if (element.Name == W.tc) { - // Check if the table cell contains any paragraph elements + // Check if the table cell contains any block-level elements + // Valid block-level elements in a table cell: p (paragraph), tbl (table), sdt (structured document tag), customXml var nodesList = transformedNodes.ToList(); - var hasParagraph = nodesList.Any(n => n is XElement xe && xe.Name == W.p); - if (!hasParagraph) + var hasBlockLevelContent = nodesList.Any(n => n is XElement xe && + (xe.Name == W.p || xe.Name == W.tbl || xe.Name == W.sdt || xe.Name == W.customXml)); + if (!hasBlockLevelContent) { - // avoid empty table cells, which are invalid -- add an empty paragraph back in + // Table cells must contain at least one block-level element -- add an empty paragraph nodesList.Add(new XElement(W.p)); } transformedNodes = nodesList;