diff options
| author | Michael Williamson <mike@zwobble.org> | 2025-06-08 10:02:56 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2025-06-08 10:02:56 +0100 |
| commit | 7fa2cbcfafd1acf12d288a578ee52dc893d2b874 (patch) | |
| tree | 139f9f21ab70e089f5294128a79550feb7fbf7f3 /src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java | |
| parent | 5d5660e3f75b4d3b4e4fee1b7929a0ba2fb8bd16 (diff) | |
Handle SDTs representing checkboxes wrapped in other elements
Diffstat (limited to 'src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java')
| -rw-r--r-- | src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java | 67 |
1 files changed, 59 insertions, 8 deletions
diff --git a/src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java b/src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java index 161ef91..30579ff 100644 --- a/src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java +++ b/src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java @@ -711,18 +711,69 @@ class StatefulBodyXmlReader { } private ReadResult readSdt(XmlElement element) { - Optional<XmlElement> checkbox = element - .findChildOrEmpty("w:sdtPr") - .findChild("wordml:checkbox"); + ReadResult contentResult = readElements( + element.findChildOrEmpty("w:sdtContent").getChildren() + ); + return contentResult.map(content -> { + // From the WordML standard: https://learn.microsoft.com/en-us/openspecs/office_standards/ms-docx/3350cb64-931f-41f7-8824-f18b2568ce66 + // + // > A CT_SdtCheckbox element that specifies that the parent + // > structured document tag is a checkbox when displayed in the + // > document. The parent structured document tag contents MUST + // > contain a single character and optionally an additional + // > character in a deleted run. + + Optional<XmlElement> checkbox = element + .findChildOrEmpty("w:sdtPr") + .findChild("wordml:checkbox"); + + if (!checkbox.isPresent()) { + return content; + } - if (checkbox.isPresent()) { Optional<XmlElement> checkedElement = checkbox.get().findChild("wordml:checked"); boolean isChecked = checkedElement.isPresent() && readBooleanAttributeValue(checkedElement.get().getAttributeOrNone("wordml:val")); - return success(new Checkbox(isChecked)); - } else { - return readElements(element.findChildOrEmpty("w:sdtContent").getChildren()); - } + Checkbox documentCheckbox = new Checkbox(isChecked); + + MutableBoolean hasCheckbox = new MutableBoolean(false); + List<DocumentElement> replacedContent = Lists.eagerMap( + content, + transformElementsOfType(Text.class, text -> { + if (text.getValue().length() > 0 && !hasCheckbox.get()) { + hasCheckbox.set(true); + return documentCheckbox; + } else { + return text; + } + }) + ); + + if (hasCheckbox.get()) { + return replacedContent; + } else { + return list(documentCheckbox); + } + }); + } + + private <T extends DocumentElement> Function<DocumentElement, DocumentElement> transformElementsOfType( + Class<T> elementClass, + Function<T, DocumentElement> transform + ) { + return element -> { + if (element instanceof HasChildren) { + element = ((HasChildren<DocumentElement>) element).replaceChildren( + Lists.eagerMap(((HasChildren<?>) element).getChildren(), transformElementsOfType(elementClass, transform)) + ); + } + + if (elementClass.isInstance(element)) { + return transform.apply((T) element); + } else { + return element; + } + }; } private String relationshipIdToDocxPath(String relationshipId) { |
