diff options
| author | Michael Williamson <mike@zwobble.org> | 2016-02-16 22:30:30 +0000 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2016-02-16 22:30:30 +0000 |
| commit | 95836987d6cef1a80035a685057567a4285c9f1a (patch) | |
| tree | 8615a1fe6358824f0bb74d54cd50c43c0b7ac035 /src | |
| parent | 6181e50cc197f5f9a71374efe256410e1eceffe3 (diff) | |
Wire up relationships and note reading
Diffstat (limited to 'src')
5 files changed, 114 insertions, 18 deletions
diff --git a/src/main/java/org/zwobble/mammoth/Mammoth.java b/src/main/java/org/zwobble/mammoth/Mammoth.java index 5830c6a..1e14482 100644 --- a/src/main/java/org/zwobble/mammoth/Mammoth.java +++ b/src/main/java/org/zwobble/mammoth/Mammoth.java @@ -4,6 +4,7 @@ import org.zwobble.mammoth.documents.Notes; import org.zwobble.mammoth.docx.*; import org.zwobble.mammoth.html.Html; import org.zwobble.mammoth.results.Result; +import org.zwobble.mammoth.util.MammothLists; import org.zwobble.mammoth.xml.XmlElement; import java.io.File; @@ -11,27 +12,38 @@ import java.io.IOException; import java.util.Optional; import java.util.zip.ZipFile; +import static org.zwobble.mammoth.util.MammothLists.list; + public class Mammoth { + @FunctionalInterface + private interface BodyReaders { + BodyXmlReader forName(String name); + } + + // TODO: provide Options builder public static Result<String> convertToHtml(File file) { + // TODO: prefix + String idPrefix = "document"; + return convertToHtml(file, idPrefix); + } + + public static Result<String> convertToHtml(File file, String idPrefix) { try (DocxFile zipFile = new ZippedDocxFile(new ZipFile(file))) { Styles styles = readStyles(zipFile); Numbering numbering = Numbering.EMPTY; - Relationships relationships = Relationships.EMPTY; ContentTypes contentTypes = ContentTypes.DEFAULT; - Notes notes = Notes.EMPTY; FileReader fileReader = uri -> { throw new UnsupportedOperationException(); }; - DocumentXmlReader reader = new DocumentXmlReader(new BodyXmlReader( - styles, - numbering, - relationships, - contentTypes, - zipFile, - fileReader), notes); - // TODO: prefix - String idPrefix = "document"; - return reader.readElement(parseOfficeXml(zipFile, "word/document.xml")) + BodyReaders bodyReaders = name -> { + Relationships relationships = readRelationships(zipFile, name); + return new BodyXmlReader(styles, numbering, relationships, contentTypes, zipFile, fileReader); + }; + return readNotes(zipFile, bodyReaders) + .flatMap(notes -> { + DocumentXmlReader reader = new DocumentXmlReader(bodyReaders.forName("document"), notes); + return reader.readElement(parseOfficeXml(zipFile, "word/document.xml")); + }) .map(nodes -> DocumentConverter.convertToHtml(idPrefix, nodes)) .map(Html::stripEmpty) .map(Html::collapse) @@ -41,18 +53,41 @@ public class Mammoth { } } - private static Styles readStyles(DocxFile file) throws IOException { + private static Result<Notes> readNotes(DocxFile file, BodyReaders bodyReaders) { + return Result.map( + tryParseOfficeXml(file, "word/footnotes.xml") + .map(NotesXmlReader.footnote(bodyReaders.forName("footnotes"))::readElement) + .orElse(Result.success(list())), + tryParseOfficeXml(file, "word/endnotes.xml") + .map(NotesXmlReader.endnote(bodyReaders.forName("endnotes"))::readElement) + .orElse(Result.success(list())), + MammothLists::concat).map(Notes::new); + } + + private static Styles readStyles(DocxFile file) { return tryParseOfficeXml(file, "word/styles.xml") .map(StylesXml::readStylesXmlElement) .orElse(Styles.EMPTY); } - private static Optional<XmlElement> tryParseOfficeXml(DocxFile zipFile, String name) throws IOException { - return zipFile.tryGetInputStream(name).map(OfficeXml::parseXml); + private static Relationships readRelationships(DocxFile zipFile, String name) { + return tryParseOfficeXml(zipFile, "word/_rels/" + name + ".xml.rels") + .map(RelationshipsXml::readRelationshipsXmlElement) + .orElse(Relationships.EMPTY); + } + + private static Optional<XmlElement> tryParseOfficeXml(DocxFile zipFile, String name) { + try { + return zipFile.tryGetInputStream(name).map(OfficeXml::parseXml); + } catch (IOException exception) { + // TODO: wrap in more specific exception and catch at the top + throw new RuntimeException(exception); + } } - private static XmlElement parseOfficeXml(DocxFile zipFile, String name) throws IOException { + private static XmlElement parseOfficeXml(DocxFile zipFile, String name) { return tryParseOfficeXml(zipFile, name) - .orElseThrow(() -> new IOException("Missing entry in file: " + name)); + // TODO: wrap in more specific exception and catch at the top + .orElseThrow(() -> new RuntimeException(new IOException("Missing entry in file: " + name))); } } diff --git a/src/main/java/org/zwobble/mammoth/docx/NotesXmlReader.java b/src/main/java/org/zwobble/mammoth/docx/NotesXmlReader.java index 726c476..d3c6532 100644 --- a/src/main/java/org/zwobble/mammoth/docx/NotesXmlReader.java +++ b/src/main/java/org/zwobble/mammoth/docx/NotesXmlReader.java @@ -15,6 +15,10 @@ public class NotesXmlReader { return new NotesXmlReader(bodyReader, "footnote", NoteType.FOOTNOTE); } + public static NotesXmlReader endnote(BodyXmlReader bodyReader) { + return new NotesXmlReader(bodyReader, "endnote", NoteType.ENDNOTE); + } + private final BodyXmlReader bodyReader; private final String tagName; private final NoteType noteType; diff --git a/src/main/java/org/zwobble/mammoth/results/Result.java b/src/main/java/org/zwobble/mammoth/results/Result.java index be0819a..7e607f0 100644 --- a/src/main/java/org/zwobble/mammoth/results/Result.java +++ b/src/main/java/org/zwobble/mammoth/results/Result.java @@ -2,9 +2,11 @@ package org.zwobble.mammoth.results; import com.google.common.collect.ImmutableList; import org.zwobble.mammoth.documents.Style; +import org.zwobble.mammoth.util.MammothLists; import java.util.List; import java.util.Optional; +import java.util.function.BiFunction; import java.util.function.Function; import static org.zwobble.mammoth.util.MammothLists.list; @@ -20,6 +22,16 @@ public class Result<T> { return new Result<>(elements.build(), warnings.build()); } + public static <T1, T2, R> Result<R> map( + Result<T1> first, + Result<T2> second, + BiFunction<T1, T2, R> function) + { + return new Result<>( + function.apply(first.value, second.value), + MammothLists.concat(first.warnings, second.warnings)); + } + public static Result<Optional<Style>> empty() { return new Result<>(Optional.empty(), list()); } @@ -47,4 +59,11 @@ public class Result<T> { public <R> Result<R> map(Function<T, R> function) { return new Result<>(function.apply(value), warnings); } + + public <R> Result<R> flatMap(Function<T, Result<R>> function) { + Result<R> intermediateResult = function.apply(value); + return new Result<>( + intermediateResult.getValue(), + MammothLists.concat(warnings, intermediateResult.warnings)); + } } diff --git a/src/main/java/org/zwobble/mammoth/util/MammothLists.java b/src/main/java/org/zwobble/mammoth/util/MammothLists.java index bed3aa8..497d1b3 100644 --- a/src/main/java/org/zwobble/mammoth/util/MammothLists.java +++ b/src/main/java/org/zwobble/mammoth/util/MammothLists.java @@ -24,7 +24,7 @@ public class MammothLists { return concat(list(head), tail); } - private static <T> List<T> concat(Iterable<T> first, Iterable<T> second) { + public static <T> List<T> concat(Iterable<T> first, Iterable<T> second) { return ImmutableList.copyOf(Iterables.concat(first, second)); } diff --git a/src/test/java/org/zwobble/mammoth/tests/MammothTests.java b/src/test/java/org/zwobble/mammoth/tests/MammothTests.java index 7e326f6..9a44cbf 100644 --- a/src/test/java/org/zwobble/mammoth/tests/MammothTests.java +++ b/src/test/java/org/zwobble/mammoth/tests/MammothTests.java @@ -32,8 +32,46 @@ public class MammothTests { deepEquals(success("<p>This XML has a byte order mark.</p>"))); } + @Test + public void footnotesAreAppendedToText() { + assertThat( + convertToHtml("footnotes.docx", "doc-42"), + deepEquals(success( + "<p>Ouch" + + "<sup><a href=\"#doc-42-footnote-1\" id=\"doc-42-footnote-ref-1\">[1]</a></sup>." + + "<sup><a href=\"#doc-42-footnote-2\" id=\"doc-42-footnote-ref-2\">[2]</a></sup></p>" + + "<ol><li id=\"doc-42-footnote-1\"><p> A tachyon walks into a bar. <a href=\"#doc-42-footnote-ref-1\">↑</a></p></li>" + + "<li id=\"doc-42-footnote-2\"><p> Fin. <a href=\"#doc-42-footnote-ref-2\">↑</a></p></li></ol>"))); + } + + @Test + public void endNotesAreAppendedToText() { + assertThat( + convertToHtml("endnotes.docx", "doc-42"), + deepEquals(success( + "<p>Ouch" + + "<sup><a href=\"#doc-42-endnote-2\" id=\"doc-42-endnote-ref-2\">[1]</a></sup>." + + "<sup><a href=\"#doc-42-endnote-3\" id=\"doc-42-endnote-ref-3\">[2]</a></sup></p>" + + "<ol><li id=\"doc-42-endnote-2\"><p> A tachyon walks into a bar. <a href=\"#doc-42-endnote-ref-2\">↑</a></p></li>" + + "<li id=\"doc-42-endnote-3\"><p> Fin. <a href=\"#doc-42-endnote-ref-3\">↑</a></p></li></ol>"))); + } + + @Test + public void relationshipsAreReadForEachFileContainingBodyXml() { + assertThat( + convertToHtml("footnote-hyperlink.docx", "doc-42"), + deepEquals(success( + "<p><sup><a href=\"#doc-42-footnote-1\" id=\"doc-42-footnote-ref-1\">[1]</a></sup></p>" + + "<ol><li id=\"doc-42-footnote-1\"><p> <a href=\"http://www.example.com\">Example</a> <a href=\"#doc-42-footnote-ref-1\">↑</a></p></li></ol>"))); + } + private Result<String> convertToHtml(String name) { File file = TestData.file(name); return Mammoth.convertToHtml(file); } + + private Result<String> convertToHtml(String name, String idPrefix) { + File file = TestData.file(name); + return Mammoth.convertToHtml(file, idPrefix); + } } |
