diff options
| author | Michael Williamson <mike@zwobble.org> | 2023-05-20 20:47:25 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2023-05-20 20:47:25 +0100 |
| commit | 0caa67864e1ece83b516a3d29bd560df7599896e (patch) | |
| tree | e4e351399ebab6830467e95162098cbe77007671 | |
| parent | 04b7f0a28cac8ed5b43ad7f806f6d38873dbd04e (diff) | |
Support merged paragraphs when revisions are tracked
5 files changed, 90 insertions, 7 deletions
@@ -1,3 +1,7 @@ +# 1.6.0 + +* Support merged paragraphs when revisions are tracked. + # 1.5.0 * Convert symbols in supported fonts to corresponding Unicode characters. diff --git a/src/main/java/org/zwobble/mammoth/internal/docx/BodyXmlReader.java b/src/main/java/org/zwobble/mammoth/internal/docx/BodyXmlReader.java index ace6628..4282bf6 100644 --- a/src/main/java/org/zwobble/mammoth/internal/docx/BodyXmlReader.java +++ b/src/main/java/org/zwobble/mammoth/internal/docx/BodyXmlReader.java @@ -29,7 +29,7 @@ public class BodyXmlReader { this.fileReader = fileReader; } - ReadResult readElements(Iterable<XmlNode> nodes) { + public ReadResult readElements(Iterable<? extends XmlNode> nodes) { return new StatefulBodyXmlReader( styles, numbering, 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 b549387..3be34ad 100644 --- a/src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java +++ b/src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java @@ -19,6 +19,7 @@ import static org.zwobble.mammoth.internal.docx.ReadResult.*; import static org.zwobble.mammoth.internal.docx.Uris.uriToZipEntryName; import static org.zwobble.mammoth.internal.util.Iterables.lazyFilter; import static org.zwobble.mammoth.internal.util.Iterables.tryGetLast; +import static org.zwobble.mammoth.internal.util.Lists.eagerConcat; import static org.zwobble.mammoth.internal.util.Lists.list; import static org.zwobble.mammoth.internal.util.Maps.entry; import static org.zwobble.mammoth.internal.util.Maps.lookup; @@ -36,6 +37,7 @@ class StatefulBodyXmlReader { private final FileReader fileReader; private final StringBuilder currentInstrText; private final Queue<ComplexField> complexFieldStack; + private List<XmlNode> deletedParagraphContents; private interface ComplexField { ComplexField UNKNOWN = new ComplexField() {}; @@ -70,6 +72,7 @@ class StatefulBodyXmlReader { this.fileReader = fileReader; this.currentInstrText = new StringBuilder(); this.complexFieldStack = Queues.stack(); + this.deletedParagraphContents = new ArrayList<>(); } ReadResult readElement(XmlElement element) { @@ -249,17 +252,33 @@ class StatefulBodyXmlReader { return readStyle(properties, "w:rStyle", "Run", styles::findCharacterStyleById); } - ReadResult readElements(Iterable<XmlNode> nodes) { + ReadResult readElements(Iterable<? extends XmlNode> nodes) { return ReadResult.flatMap(lazyFilter(nodes, XmlElement.class), this::readElement); } private ReadResult readParagraph(XmlElement element) { XmlElementLike properties = element.findChildOrEmpty("w:pPr"); - ParagraphIndent indent = readParagraphIndent(properties); - return ReadResult.map( - readParagraphStyle(properties), - readElements(element.getChildren()), - (style, children) -> new Paragraph(style, readNumbering(style, properties), indent, children)).appendExtra(); + + boolean isDeleted = properties + .findChildOrEmpty("w:rPr") + .findChild("w:del") + .isPresent(); + + if (isDeleted) { + deletedParagraphContents.addAll(element.getChildren()); + return ReadResult.success(list()); + } else { + ParagraphIndent indent = readParagraphIndent(properties); + List<XmlNode> childrenXml = element.getChildren(); + if (!deletedParagraphContents.isEmpty()) { + childrenXml = eagerConcat(deletedParagraphContents, childrenXml); + deletedParagraphContents = new ArrayList<>(); + } + return ReadResult.map( + readParagraphStyle(properties), + readElements(childrenXml), + (style, children) -> new Paragraph(style, readNumbering(style, properties), indent, children)).appendExtra(); + } } private ReadResult readFieldChar(XmlElement element) { 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 1898897..c8b6c7c 100644 --- a/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java +++ b/src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java @@ -264,6 +264,62 @@ public class BodyXmlTests { hasNumbering(Optional.empty())); } + @Test + public void contentOfDeletedParagraphIsPreprendedToNextParagraph() { + Style heading1 = new Style("Heading1", Optional.of("Heading 1")); + Style heading2 = new Style("Heading2", Optional.of("Heading 2")); + Styles styles = new Styles( + map( + "Heading1", heading1, + "Heading2", heading2 + ), + map(), + map(), + map() + ); + List<XmlElement> bodyXml = list( + element("w:p", list( + element("w:pPr", list( + element("w:pStyle", map("w:val", "Heading1")), + element("w:rPr", list( + element("w:del") + )) + )), + runXml("One") + )), + element("w:p", list( + element("w:pPr", list( + element("w:pStyle", map("w:val", "Heading2")) + )), + runXml("Two") + )), + // Include a second paragraph that isn't deleted to ensure we only add + // the deleted paragraph contents once. + element("w:p", list( + runXml("Three") + )) + ); + + BodyXmlReader reader = bodyReader(styles); + InternalResult<List<DocumentElement>> result = reader.readElements(bodyXml).toResult(); + + assertThat(result.getWarnings(), emptyIterable()); + assertThat(result.getValue(), contains( + isParagraph( + hasParagraphStyle(equalTo(Optional.of(heading2))), + hasChildren( + isRun(run(withChildren(text("One")))), + isRun(run(withChildren(text("Two")))) + ) + ), + isParagraph( + hasChildren( + isRun(run(withChildren(text("Three")))) + ) + ) + )); + } + @Nested public class ComplexFieldsTests { private final String URI = "http://example.com"; 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 53632c1..4f3628e 100644 --- a/src/test/java/org/zwobble/mammoth/tests/docx/DocumentMatchers.java +++ b/src/test/java/org/zwobble/mammoth/tests/docx/DocumentMatchers.java @@ -37,6 +37,10 @@ public class DocumentMatchers { return cast(Paragraph.class, allOf(matchers)); } + static Matcher<Paragraph> hasParagraphStyle(Matcher<Optional<Style>> style) { + return hasProperty("style", style); + } + static Matcher<DocumentElement> isEmptyRun() { return isRun(hasChildren()); } |
