aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2024-11-30 14:20:42 +0000
committerMichael Williamson <mike@zwobble.org>2024-11-30 14:20:42 +0000
commit57a988d26011f58ee2cc9e9bb9f9bbd7c8de32be (patch)
treef49d1dbaffe74c0471e972f123bba64de41aa7b3
parenta2d7d044d9add9f0c381fdd8821902e08b46e1ad (diff)
Read complex field checkboxes, always unchecked
-rw-r--r--src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java66
-rw-r--r--src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java55
-rw-r--r--src/test/java/org/zwobble/mammoth/tests/docx/DocumentMatchers.java5
3 files changed, 112 insertions, 14 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 246f69e..c8a4d9b 100644
--- a/src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java
+++ b/src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java
@@ -43,9 +43,25 @@ class StatefulBodyXmlReader {
private interface ComplexField {
ComplexField UNKNOWN = new ComplexField() {};
+ static ComplexField begin(XmlElement fldChar) {
+ return new BeginComplexField(fldChar);
+ }
+
static ComplexField hyperlink(Function<List<DocumentElement>, Hyperlink> childrenToHyperlink) {
return new HyperlinkComplexField(childrenToHyperlink);
}
+
+ static ComplexField checkbox(boolean checked) {
+ return new CheckboxComplexField(checked);
+ }
+ }
+
+ private static class BeginComplexField implements ComplexField {
+ private final XmlElement fldChar;
+
+ private BeginComplexField(XmlElement fldChar) {
+ this.fldChar = fldChar;
+ }
}
private static class HyperlinkComplexField implements ComplexField {
@@ -56,6 +72,14 @@ class StatefulBodyXmlReader {
}
}
+ private static class CheckboxComplexField implements ComplexField {
+ private final boolean checked;
+
+ private CheckboxComplexField(boolean checked) {
+ this.checked = checked;
+ }
+ }
+
StatefulBodyXmlReader(
Styles styles,
Numbering numbering,
@@ -291,42 +315,56 @@ class StatefulBodyXmlReader {
private ReadResult readFieldChar(XmlElement element) {
String type = element.getAttributeOrNone("w:fldCharType").orElse("");
if (type.equals("begin")) {
- complexFieldStack.add(ComplexField.UNKNOWN);
+ complexFieldStack.add(ComplexField.begin(element));
currentInstrText.setLength(0);
} else if (type.equals("end")) {
- complexFieldStack.remove();
+ ComplexField complexField = complexFieldStack.remove();
+ if (complexField instanceof BeginComplexField) {
+ complexField = parseCurrentInstrText(complexField);
+ }
+ if (complexField instanceof CheckboxComplexField) {
+ return success(new Checkbox(((CheckboxComplexField) complexField).checked));
+ }
} else if (type.equals("separate")) {
- String instrText = currentInstrText.toString();
- ComplexField complexField = parseHyperlinkFieldCode(instrText)
- .map(href -> ComplexField.hyperlink(href))
- .orElse(ComplexField.UNKNOWN);
- complexFieldStack.remove();
+ ComplexField complexFieldSeparate = complexFieldStack.remove();
+ ComplexField complexField = parseCurrentInstrText(complexFieldSeparate);
complexFieldStack.add(complexField);
}
return ReadResult.EMPTY_SUCCESS;
}
- private ReadResult readInstrText(XmlElement element) {
- currentInstrText.append(element.innerText());
- return ReadResult.EMPTY_SUCCESS;
+ private ComplexField parseCurrentInstrText(ComplexField complexField) {
+ String instrText = currentInstrText.toString();
+ return parseInstrText(instrText, complexField);
}
- private Optional<Function<List<DocumentElement>, Hyperlink>> parseHyperlinkFieldCode(String instrText) {
+ private ComplexField parseInstrText(String instrText, ComplexField complexField) {
Pattern externalLinkPattern = Pattern.compile("\\s*HYPERLINK \"(.*)\"");
Matcher externalLinkMatcher = externalLinkPattern.matcher(instrText);
if (externalLinkMatcher.lookingAt()) {
String href = externalLinkMatcher.group(1);
- return Optional.of(children -> Hyperlink.href(href, Optional.empty(), children));
+ return ComplexField.hyperlink(children -> Hyperlink.href(href, Optional.empty(), children));
}
Pattern internalLinkPattern = Pattern.compile("\\s*HYPERLINK\\s+\\\\l\\s+\"(.*)\"");
Matcher internalLinkMatcher = internalLinkPattern.matcher(instrText);
if (internalLinkMatcher.lookingAt()) {
String anchor = internalLinkMatcher.group(1);
- return Optional.of(children -> Hyperlink.anchor(anchor, Optional.empty(), children));
+ return ComplexField.hyperlink(children -> Hyperlink.anchor(anchor, Optional.empty(), children));
}
- return Optional.empty();
+ Pattern checkboxPattern = Pattern.compile("\\s*FORMCHECKBOX\\s*");
+ Matcher checkboxMatcher = checkboxPattern.matcher(instrText);
+ if (checkboxMatcher.lookingAt()) {
+ return ComplexField.checkbox(false);
+ }
+
+ return ComplexField.UNKNOWN;
+ }
+
+ private ReadResult readInstrText(XmlElement element) {
+ currentInstrText.append(element.innerText());
+ return ReadResult.EMPTY_SUCCESS;
}
private InternalResult<Optional<Style>> readParagraphStyle(XmlElementLike properties) {
diff --git a/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java b/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java
index 3cfb161..c859be4 100644
--- a/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java
+++ b/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java
@@ -573,6 +573,61 @@ public class BodyXmlTests {
}
}
+ @Nested
+ public class CheckboxTests {
+ @Test
+ public void complexFieldCheckboxWithoutSeparateIsRead() {
+ XmlElement element = element("w:p", list(
+ element("w:r", list(
+ element("w:fldChar", map("w:fldCharType", "begin"))
+ )),
+ element("w:instrText", list(
+ textXml(" FORMCHECKBOX ")
+ )),
+ element("w:r", list(
+ element("w:fldChar", map("w:fldCharType", "end"))
+ ))
+ ));
+
+ DocumentElement paragraph = readSuccess(bodyReader(), element);
+
+ assertThat(paragraph, isParagraph(hasChildren(
+ isEmptyRun(),
+ isRun(hasChildren(
+ isCheckbox()
+ ))
+ )));
+ }
+
+ @Test
+ public void complexFieldCheckboxWithSeparateIsRead() {
+ XmlElement element = element("w:p", list(
+ element("w:r", list(
+ element("w:fldChar", map("w:fldCharType", "begin"))
+ )),
+ element("w:instrText", list(
+ textXml(" FORMCHECKBOX ")
+ )),
+ element("w:r", list(
+ element("w:fldChar", map("w:fldCharType", "separate"))
+ )),
+ element("w:r", list(
+ element("w:fldChar", map("w:fldCharType", "end"))
+ ))
+ ));
+
+ DocumentElement paragraph = readSuccess(bodyReader(), element);
+
+ assertThat(paragraph, isParagraph(hasChildren(
+ isEmptyRun(),
+ isEmptyRun(),
+ isRun(hasChildren(
+ isCheckbox()
+ ))
+ )));
+ }
+ }
+
@Test
public void runHasNoStyleIfItHasNoProperties() {
XmlElement element = runXml(list());
diff --git a/src/test/java/org/zwobble/mammoth/tests/docx/DocumentMatchers.java b/src/test/java/org/zwobble/mammoth/tests/docx/DocumentMatchers.java
index 4f3628e..fae84b2 100644
--- a/src/test/java/org/zwobble/mammoth/tests/docx/DocumentMatchers.java
+++ b/src/test/java/org/zwobble/mammoth/tests/docx/DocumentMatchers.java
@@ -91,6 +91,11 @@ public class DocumentMatchers {
return cast(Hyperlink.class, allOf(matchers));
}
+ @SafeVarargs
+ static Matcher<DocumentElement> isCheckbox(Matcher<? super Checkbox>... matchers) {
+ return cast(Checkbox.class, allOf(matchers));
+ }
+
static Matcher<Hyperlink> hasHref(String href) {
return hasProperty("href", equalTo(Optional.of(href)));
}