From 29a3d3491a2796c5a1e772c2f15deb2a9a2e9376 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Sat, 27 Jan 2018 18:17:22 +0000 Subject: Find comments part using document relationships --- .../mammoth/internal/docx/DocumentReader.java | 62 +++++++++++++++++----- .../org/zwobble/mammoth/internal/util/Maps.java | 9 ++++ .../mammoth/tests/docx/DocumentReaderTests.java | 52 +++++++++++++++++- 3 files changed, 108 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/zwobble/mammoth/internal/docx/DocumentReader.java b/src/main/java/org/zwobble/mammoth/internal/docx/DocumentReader.java index 1e3b3e3..6176aec 100644 --- a/src/main/java/org/zwobble/mammoth/internal/docx/DocumentReader.java +++ b/src/main/java/org/zwobble/mammoth/internal/docx/DocumentReader.java @@ -15,6 +15,7 @@ import java.nio.file.Path; import java.util.List; import java.util.Optional; import java.util.function.BiFunction; +import java.util.function.Function; import static org.zwobble.mammoth.internal.util.Lists.*; import static org.zwobble.mammoth.internal.util.Strings.trimLeft; @@ -59,9 +60,11 @@ public class DocumentReader { public static class PartPaths { private final String mainDocument; + private final String comments; - public PartPaths(String mainDocument) { + public PartPaths(String mainDocument, String comments) { this.mainDocument = mainDocument; + this.comments = comments; } public String getMainDocument() { @@ -69,7 +72,7 @@ public class DocumentReader { } public String getComments() { - return "word/comments.xml"; + return comments; } public String getEndnotes() { @@ -92,7 +95,21 @@ public class DocumentReader { public static PartPaths findPartPaths(Archive archive) { Relationships packageRelationships = readPackageRelationships(archive); String documentFilename = findDocumentFilename(archive, packageRelationships); - return new PartPaths(documentFilename); + + Relationships documentRelationships = readRelationships( + archive, + findRelationshipsPathFor(documentFilename) + ); + + Function find = name -> findPartPath( + archive, + documentRelationships, + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/" + name, + ZipPaths.splitPath(documentFilename).getDirname(), + "word/" + name + ".xml" + ); + + return new PartPaths(documentFilename, find.apply("comments")); } private static Relationships readPackageRelationships(Archive archive) { @@ -101,18 +118,37 @@ public class DocumentReader { private static String findDocumentFilename(Archive archive, Relationships packageRelationships) { String officeDocumentType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"; - List targets = eagerConcat( - eagerMap( - packageRelationships.findTargetsByType(officeDocumentType), - target -> trimLeft(target, '/') - ), - list("word/document.xml") + String mainDocumentPath = findPartPath( + archive, + packageRelationships, + officeDocumentType, + "", + "word/document.xml" ); - List validTargets = eagerFilter(targets, archive::exists); - return tryGetFirst(validTargets) - .orElseThrow(() -> new PassThroughException( + + if (archive.exists(mainDocumentPath)) { + return mainDocumentPath; + } else { + throw new PassThroughException( new IOException("Could not find main document part. Are you sure this is a valid .docx file?") - )); + ); + } + } + + private static String findPartPath( + Archive archive, + Relationships relationships, + String relationshipType, + String basePath, + String fallbackPath + ) { + + List targets = eagerMap( + relationships.findTargetsByType(relationshipType), + target -> trimLeft(ZipPaths.joinPath(basePath, target), '/') + ); + List validTargets = eagerFilter(targets, archive::exists); + return tryGetFirst(validTargets).orElse(fallbackPath); } private static InternalResult> readComments(PartWithBodyReader partReader, PartPaths partPaths) { diff --git a/src/main/java/org/zwobble/mammoth/internal/util/Maps.java b/src/main/java/org/zwobble/mammoth/internal/util/Maps.java index f96c1f5..e053c90 100644 --- a/src/main/java/org/zwobble/mammoth/internal/util/Maps.java +++ b/src/main/java/org/zwobble/mammoth/internal/util/Maps.java @@ -27,6 +27,15 @@ public class Maps { return map; } + public static Map map(K key1, V value1, K key2, V value2, K key3, V value3, K key4, V value4) { + Map map = new HashMap<>(); + map.put(key1, value1); + map.put(key2, value2); + map.put(key3, value3); + map.put(key4, value4); + return map; + } + public static Map mutableMap(K key1, V value1) { Map map = new HashMap<>(); map.put(key1, value1); diff --git a/src/test/java/org/zwobble/mammoth/tests/docx/DocumentReaderTests.java b/src/test/java/org/zwobble/mammoth/tests/docx/DocumentReaderTests.java index ddccd9c..bce431a 100644 --- a/src/test/java/org/zwobble/mammoth/tests/docx/DocumentReaderTests.java +++ b/src/test/java/org/zwobble/mammoth/tests/docx/DocumentReaderTests.java @@ -103,7 +103,6 @@ public class DocumentReaderTests { )); DocumentReader.PartPaths partPaths = DocumentReader.findPartPaths(archive); - assertThat(partPaths.getMainDocument(), equalTo("word/document2.xml")); } @@ -114,8 +113,57 @@ public class DocumentReaderTests { )); DocumentReader.PartPaths partPaths = DocumentReader.findPartPaths(archive); - assertThat(partPaths.getMainDocument(), equalTo("word/document.xml")); } + @Test + public void commentsPartIsFoundUsingMainDocumentRelationships() { + InMemoryArchive archive = InMemoryArchive.fromStrings(map( + "_rels/.rels", XmlWriter.toString( + element("Relationships", list( + element("Relationship", map( + "Id", "rId1", + "Target", "/word/document.xml", + "Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" + )) + )), + relationshipsNamespaces + ), + "word/document.xml", " ", + "word/_rels/document.xml.rels", XmlWriter.toString( + element("Relationships", list( + element("Relationship", map( + "Id", "rId2", + "Target", "target-path.xml", + "Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments" + )) + )), + relationshipsNamespaces + ), + "word/target-path.xml", " " + )); + + DocumentReader.PartPaths partPaths = DocumentReader.findPartPaths(archive); + assertThat(partPaths.getComments(), equalTo("word/target-path.xml")); + } + + @Test + public void whenRelationshipsForCommentsCannotBeFoundThenFallbackIsUsed() { + InMemoryArchive archive = InMemoryArchive.fromStrings(map( + "word/document.xml", " ", + "_rels/.rels", XmlWriter.toString( + element("Relationships", list( + element("Relationship", map( + "Id", "rId1", + "Target", "/word/document.xml", + "Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" + )) + )), + relationshipsNamespaces + ) + )); + + DocumentReader.PartPaths partPaths = DocumentReader.findPartPaths(archive); + assertThat(partPaths.getComments(), equalTo("word/comments.xml")); + } } } -- cgit v1.2.3