summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2023-05-20 20:47:25 +0100
committerMichael Williamson <mike@zwobble.org>2023-05-20 20:47:25 +0100
commit0caa67864e1ece83b516a3d29bd560df7599896e (patch)
treee4e351399ebab6830467e95162098cbe77007671 /src
parent04b7f0a28cac8ed5b43ad7f806f6d38873dbd04e (diff)
Support merged paragraphs when revisions are tracked
Diffstat (limited to 'src')
-rw-r--r--src/main/java/org/zwobble/mammoth/internal/docx/BodyXmlReader.java2
-rw-r--r--src/main/java/org/zwobble/mammoth/internal/docx/StatefulBodyXmlReader.java31
-rw-r--r--src/test/java/org/zwobble/mammoth/tests/docx/BodyXmlTests.java56
-rw-r--r--src/test/java/org/zwobble/mammoth/tests/docx/DocumentMatchers.java4
4 files changed, 86 insertions, 7 deletions
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());
}