Skip to content

Commit

Permalink
Convert SDT checkboxes to checkbox inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
mwilliamson committed Dec 30, 2024
1 parent 4289436 commit 13bf5b5
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 4 deletions.
5 changes: 5 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 1.9.0

* Detect checkboxes, both as complex fields and structured document tags, and
convert them to checkbox inputs.

# 1.8.0

* Add style mapping for highlights.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ public class OfficeXml {
.put("mc", "http://schemas.openxmlformats.org/markup-compatibility/2006")
.put("v", "urn:schemas-microsoft-com:vml")
.put("office-word", "urn:schemas-microsoft-com:office:word")

// [MS-DOCX]: Word Extensions to the Office Open XML (.docx) File Format
// https://learn.microsoft.com/en-us/openspecs/office_standards/ms-docx/b839fe1f-e1ca-4fa6-8c26-5954d0abbccd
.put("wordml", "http://schemas.microsoft.com/office/word/2010/wordml")

.build();

public static XmlElement parseXml(InputStream inputStream) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,12 +257,16 @@ private boolean isSmallCaps(XmlElementLike properties) {

private boolean readBooleanElement(XmlElementLike properties, String tagName) {
return properties.findChild(tagName)
.map(child -> child.getAttributeOrNone("w:val")
.map(value -> !value.equals("false") && !value.equals("0"))
.orElse(true))
.map(child -> readBooleanAttributeValue(child.getAttributeOrNone("w:val")))
.orElse(false);
}

private boolean readBooleanAttributeValue(Optional<String> valAttributeValue) {
return valAttributeValue
.map(value -> !value.equals("false") && !value.equals("0"))
.orElse(true);
}

private VerticalAlignment readVerticalAlignment(XmlElementLike properties) {
String verticalAlignment = readVal(properties, "w:vertAlign").orElse("");
switch (verticalAlignment) {
Expand Down Expand Up @@ -697,7 +701,18 @@ private ReadResult readImage(String imagePath, Optional<String> altText, InputSt
}

private ReadResult readSdt(XmlElement element) {
return readElements(element.findChildOrEmpty("w:sdtContent").getChildren());
Optional<XmlElement> checkbox = element
.findChildOrEmpty("w:sdtPr")
.findChild("wordml:checkbox");

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());
}
}

private String relationshipIdToDocxPath(String relationshipId) {
Expand Down
43 changes: 43 additions & 0 deletions src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,49 @@ public void complexFieldCheckboxWithDefault0AndChecked1IsUnchecked() {
)));
}

@Test
public void structuredDocumentTagCheckboxWithoutCheckedIsNotChecked() {
XmlElement element = element("w:sdt", list(
element("w:sdtPr", list(
element("wordml:checkbox")
))
));

DocumentElement result = readSuccess(bodyReader(), element);

assertThat(result, isCheckbox(false));
}

@Test
public void structuredDocumentTagCheckboxWithChecked0IsNotChecked() {
XmlElement element = element("w:sdt", list(
element("w:sdtPr", list(
element("wordml:checkbox", list(
element("wordml:checked", map("wordml:val", "0"))
))
))
));

DocumentElement result = readSuccess(bodyReader(), element);

assertThat(result, isCheckbox(false));
}

@Test
public void structuredDocumentTagCheckboxWithChecked1IsChecked() {
XmlElement element = element("w:sdt", list(
element("w:sdtPr", list(
element("wordml:checkbox", list(
element("wordml:checked", map("wordml:val", "1"))
))
))
));

DocumentElement result = readSuccess(bodyReader(), element);

assertThat(result, isCheckbox(true));
}

private XmlElement complexFieldCheckboxParagraph(List<XmlNode> ffDataChildren) {
return element("w:p", list(
element("w:r", list(
Expand Down

0 comments on commit 13bf5b5

Please sign in to comment.