From b693b50ba55ab80cb7df90f150bf6585ba9fdc09 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Wed, 24 Feb 2016 20:57:09 +0000 Subject: Rename DocumentConverter to DocumentToHtml --- src/main/java/org/zwobble/mammoth/Mammoth.java | 4 +- .../mammoth/internal/DocumentConverter.java | 258 --------------------- .../zwobble/mammoth/internal/DocumentToHtml.java | 258 +++++++++++++++++++++ .../mammoth/tests/DocumentConverterTests.java | 8 +- 4 files changed, 264 insertions(+), 264 deletions(-) delete mode 100644 src/main/java/org/zwobble/mammoth/internal/DocumentConverter.java create mode 100644 src/main/java/org/zwobble/mammoth/internal/DocumentToHtml.java diff --git a/src/main/java/org/zwobble/mammoth/Mammoth.java b/src/main/java/org/zwobble/mammoth/Mammoth.java index d7f5679..e979afc 100644 --- a/src/main/java/org/zwobble/mammoth/Mammoth.java +++ b/src/main/java/org/zwobble/mammoth/Mammoth.java @@ -2,7 +2,7 @@ package org.zwobble.mammoth; import com.google.common.base.Function; import com.google.common.collect.Iterables; -import org.zwobble.mammoth.internal.DocumentConverter; +import org.zwobble.mammoth.internal.DocumentToHtml; import org.zwobble.mammoth.internal.DocumentToHtmlOptions; import org.zwobble.mammoth.internal.documents.DocumentElement; import org.zwobble.mammoth.internal.documents.HasChildren; @@ -62,7 +62,7 @@ public class Mammoth { private Result convertToHtml(Optional path, DocxFile zipFile) { return readDocument(path, zipFile) - .flatMap(nodes -> DocumentConverter.convertToHtml(nodes, options)) + .flatMap(nodes -> DocumentToHtml.convertToHtml(nodes, options)) .map(Html::stripEmpty) .map(Html::collapse) .map(Html::write); diff --git a/src/main/java/org/zwobble/mammoth/internal/DocumentConverter.java b/src/main/java/org/zwobble/mammoth/internal/DocumentConverter.java deleted file mode 100644 index 4e5dc05..0000000 --- a/src/main/java/org/zwobble/mammoth/internal/DocumentConverter.java +++ /dev/null @@ -1,258 +0,0 @@ -package org.zwobble.mammoth.internal; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; -import com.google.common.io.ByteStreams; -import org.zwobble.mammoth.internal.documents.*; -import org.zwobble.mammoth.internal.html.Html; -import org.zwobble.mammoth.internal.html.HtmlNode; -import org.zwobble.mammoth.results.Result; -import org.zwobble.mammoth.results.Warning; -import org.zwobble.mammoth.internal.styles.HtmlPath; -import org.zwobble.mammoth.internal.styles.StyleMap; -import org.zwobble.mammoth.internal.util.MammothLists; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Base64; -import java.util.List; -import java.util.Map; - -import static org.zwobble.mammoth.results.Warning.warning; -import static org.zwobble.mammoth.internal.util.MammothLists.*; -import static org.zwobble.mammoth.internal.util.MammothMaps.map; - -public class DocumentConverter { - public static Result> convertToHtml(Document document, DocumentToHtmlOptions options) { - DocumentConverter documentConverter = new DocumentConverter(options); - return new Result<>( - documentConverter.convertToHtml(document), - documentConverter.warnings.build()); - } - - private static List findNotes(Document document, Iterable noteReferences) { - return ImmutableList.copyOf(Iterables.transform( - noteReferences, - // TODO: handle missing notes - reference -> document.getNotes().findNote(reference.getNoteType(), reference.getNoteId()).get())); - } - - public static Result> convertToHtml(DocumentElement element, DocumentToHtmlOptions options) { - DocumentConverter documentConverter = new DocumentConverter(options); - return new Result<>( - documentConverter.convertToHtml(element), - documentConverter.warnings.build()); - } - - private final String idPrefix; - private final boolean preserveEmptyParagraphs; - private final StyleMap styleMap; - private final List noteReferences = new ArrayList<>(); - private final ImmutableList.Builder warnings = ImmutableList.builder(); - - private DocumentConverter(DocumentToHtmlOptions options) { - this.idPrefix = options.idPrefix(); - this.preserveEmptyParagraphs = options.shouldPreserveEmptyParagraphs(); - this.styleMap = options.styleMap(); - } - - private List convertToHtml(Document document) { - List mainBody = convertChildrenToHtml(document); - // TODO: can you have note references inside a note? - List notes = findNotes(document, noteReferences); - if (notes.isEmpty()) { - return mainBody; - } else { - HtmlNode noteNode = Html.element("ol", - ImmutableList.copyOf(Iterables.transform(notes, this::convertToHtml))); - - return ImmutableList.copyOf(Iterables.concat(mainBody, list(noteNode))); - } - } - - private HtmlNode convertToHtml(Note note) { - String id = generateNoteHtmlId(note.getNoteType(), note.getId()); - String referenceId = generateNoteRefHtmlId(note.getNoteType(), note.getId()); - ImmutableList.Builder children = ImmutableList.builder(); - children.addAll(convertToHtml(note.getBody())); - // TODO: we probably want this to collapse more eagerly than other collapsible elements - // -- for instance, any paragraph will probably do, regardless of attributes. (Possible other elements will do too.) - children.add(Html.collapsibleElement("p", list( - Html.text(" "), - Html.element("a", map("href", "#" + referenceId), list(Html.text("↑")))))); - return Html.element("li", map("id", id), children.build()); - } - - private List convertToHtml(List elements) { - return eagerFlatMap( - elements, - this::convertToHtml); - } - - private List convertChildrenToHtml(HasChildren element) { - return convertToHtml(element.getChildren()); - } - - private List convertToHtml(DocumentElement element) { - return element.accept(new DocumentElementVisitor>() { - @Override - public List visit(Paragraph paragraph) { - List content = convertChildrenToHtml(paragraph); - List children = preserveEmptyParagraphs ? cons(Html.FORCE_WRITE, content) : content; - HtmlPath mapping = styleMap.getParagraphHtmlPath(paragraph) - .orElseGet(() -> { - if (paragraph.getStyle().isPresent()) { - warnings.add(warning("Unrecognised paragraph style: " + paragraph.getStyle().get().describe())); - } - return HtmlPath.element("p"); - }); - return mapping.wrap(children); - } - - @Override - public List visit(Run run) { - List nodes = convertChildrenToHtml(run); - if (run.isStrikethrough()) { - nodes = styleMap.getStrikethrough().orElse(HtmlPath.collapsibleElement("s")).wrap(nodes); - } - if (run.isUnderline()) { - nodes = styleMap.getUnderline().orElse(HtmlPath.EMPTY).wrap(nodes); - } - if (run.getVerticalAlignment() == VerticalAlignment.SUBSCRIPT) { - nodes = list(Html.collapsibleElement("sub", nodes)); - } - if (run.getVerticalAlignment() == VerticalAlignment.SUPERSCRIPT) { - nodes = list(Html.collapsibleElement("sup", nodes)); - } - if (run.isItalic()) { - nodes = list(Html.collapsibleElement("em", nodes)); - } - if (run.isBold()) { - nodes = list(Html.collapsibleElement("strong", nodes)); - } - HtmlPath mapping = styleMap.getRunHtmlPath(run) - .orElseGet(() -> { - if (run.getStyle().isPresent()) { - warnings.add(warning("Unrecognised run style: " + run.getStyle().get().describe())); - } - return HtmlPath.EMPTY; - }); - return mapping.wrap(nodes); - } - - @Override - public List visit(Text text) { - if (text.getValue().isEmpty()) { - return list(); - } else { - return list(Html.text(text.getValue())); - } - } - - @Override - public List visit(Tab tab) { - return list(Html.text("\t")); - } - - @Override - public List visit(LineBreak lineBreak) { - return list(Html.selfClosingElement("br")); - } - - @Override - public List visit(Table table) { - return list(Html.element("table", convertChildrenToHtml(table))); - } - - @Override - public List visit(TableRow tableRow) { - return list(Html.element("tr", convertChildrenToHtml(tableRow))); - } - - @Override - public List visit(TableCell tableCell) { - return list(Html.element("td", - MammothLists.cons(Html.FORCE_WRITE, convertChildrenToHtml(tableCell)))); - } - - @Override - public List visit(Hyperlink hyperlink) { - Map attributes = map("href", generateHref(hyperlink)); - return list(Html.collapsibleElement("a", attributes, convertChildrenToHtml(hyperlink))); - } - - private String generateHref(Hyperlink hyperlink) { - if (hyperlink.getHref().isPresent()) { - return hyperlink.getHref().get(); - } else if (hyperlink.getAnchor().isPresent()) { - return "#" + generateId(hyperlink.getAnchor().get()); - } else { - return ""; - } - } - - @Override - public List visit(Bookmark bookmark) { - return list(Html.element("a", map("id", generateId(bookmark.getName())), list(Html.FORCE_WRITE))); - } - - @Override - public List visit(NoteReference noteReference) { - noteReferences.add(noteReference); - String noteAnchor = generateNoteHtmlId(noteReference.getNoteType(), noteReference.getNoteId()); - String noteReferenceAnchor = generateNoteRefHtmlId(noteReference.getNoteType(), noteReference.getNoteId()); - return list(Html.element("sup", list( - Html.element("a", map("href", "#" + noteAnchor, "id", noteReferenceAnchor), list( - Html.text("[" + noteReferences.size() + "]")))))); - } - - @Override - public List visit(Image image) { - // TODO: custom image handlers - // TODO: handle empty content type - return image.getContentType() - .map(contentType -> { - try { - ImmutableMap.Builder attributes = ImmutableMap.builder(); - - String base64 = Base64.getEncoder().encodeToString(ByteStreams.toByteArray(image.open())); - String src = "data:" + contentType + ";base64," + base64; - attributes.put("src", src); - - image.getAltText().ifPresent(altText -> attributes.put("alt", altText)); - - return list(Html.selfClosingElement("img", attributes.build())); - } catch (IOException exception) { - warnings.add(warning(exception.getMessage())); - return MammothLists.list(); - } - }) - .orElse(list()); - } - }); - } - - private String generateNoteHtmlId(NoteType noteType, String noteId) { - return generateId(noteTypeToIdFragment(noteType) + "-" + noteId); - } - - private String generateNoteRefHtmlId(NoteType noteType, String noteId) { - return generateId(noteTypeToIdFragment(noteType) + "-ref-" + noteId); - } - - private String noteTypeToIdFragment(NoteType noteType) { - switch (noteType) { - case FOOTNOTE: - return "footnote"; - case ENDNOTE: - return "endnote"; - default: - throw new UnsupportedOperationException(); - } - } - - private String generateId(String bookmarkName) { - return idPrefix + bookmarkName; - } -} diff --git a/src/main/java/org/zwobble/mammoth/internal/DocumentToHtml.java b/src/main/java/org/zwobble/mammoth/internal/DocumentToHtml.java new file mode 100644 index 0000000..b501800 --- /dev/null +++ b/src/main/java/org/zwobble/mammoth/internal/DocumentToHtml.java @@ -0,0 +1,258 @@ +package org.zwobble.mammoth.internal; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import com.google.common.io.ByteStreams; +import org.zwobble.mammoth.internal.documents.*; +import org.zwobble.mammoth.internal.html.Html; +import org.zwobble.mammoth.internal.html.HtmlNode; +import org.zwobble.mammoth.results.Result; +import org.zwobble.mammoth.results.Warning; +import org.zwobble.mammoth.internal.styles.HtmlPath; +import org.zwobble.mammoth.internal.styles.StyleMap; +import org.zwobble.mammoth.internal.util.MammothLists; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; +import java.util.Map; + +import static org.zwobble.mammoth.results.Warning.warning; +import static org.zwobble.mammoth.internal.util.MammothLists.*; +import static org.zwobble.mammoth.internal.util.MammothMaps.map; + +public class DocumentToHtml { + public static Result> convertToHtml(Document document, DocumentToHtmlOptions options) { + DocumentToHtml documentConverter = new DocumentToHtml(options); + return new Result<>( + documentConverter.convertToHtml(document), + documentConverter.warnings.build()); + } + + private static List findNotes(Document document, Iterable noteReferences) { + return ImmutableList.copyOf(Iterables.transform( + noteReferences, + // TODO: handle missing notes + reference -> document.getNotes().findNote(reference.getNoteType(), reference.getNoteId()).get())); + } + + public static Result> convertToHtml(DocumentElement element, DocumentToHtmlOptions options) { + DocumentToHtml documentConverter = new DocumentToHtml(options); + return new Result<>( + documentConverter.convertToHtml(element), + documentConverter.warnings.build()); + } + + private final String idPrefix; + private final boolean preserveEmptyParagraphs; + private final StyleMap styleMap; + private final List noteReferences = new ArrayList<>(); + private final ImmutableList.Builder warnings = ImmutableList.builder(); + + private DocumentToHtml(DocumentToHtmlOptions options) { + this.idPrefix = options.idPrefix(); + this.preserveEmptyParagraphs = options.shouldPreserveEmptyParagraphs(); + this.styleMap = options.styleMap(); + } + + private List convertToHtml(Document document) { + List mainBody = convertChildrenToHtml(document); + // TODO: can you have note references inside a note? + List notes = findNotes(document, noteReferences); + if (notes.isEmpty()) { + return mainBody; + } else { + HtmlNode noteNode = Html.element("ol", + ImmutableList.copyOf(Iterables.transform(notes, this::convertToHtml))); + + return ImmutableList.copyOf(Iterables.concat(mainBody, list(noteNode))); + } + } + + private HtmlNode convertToHtml(Note note) { + String id = generateNoteHtmlId(note.getNoteType(), note.getId()); + String referenceId = generateNoteRefHtmlId(note.getNoteType(), note.getId()); + ImmutableList.Builder children = ImmutableList.builder(); + children.addAll(convertToHtml(note.getBody())); + // TODO: we probably want this to collapse more eagerly than other collapsible elements + // -- for instance, any paragraph will probably do, regardless of attributes. (Possible other elements will do too.) + children.add(Html.collapsibleElement("p", list( + Html.text(" "), + Html.element("a", map("href", "#" + referenceId), list(Html.text("↑")))))); + return Html.element("li", map("id", id), children.build()); + } + + private List convertToHtml(List elements) { + return eagerFlatMap( + elements, + this::convertToHtml); + } + + private List convertChildrenToHtml(HasChildren element) { + return convertToHtml(element.getChildren()); + } + + private List convertToHtml(DocumentElement element) { + return element.accept(new DocumentElementVisitor>() { + @Override + public List visit(Paragraph paragraph) { + List content = convertChildrenToHtml(paragraph); + List children = preserveEmptyParagraphs ? cons(Html.FORCE_WRITE, content) : content; + HtmlPath mapping = styleMap.getParagraphHtmlPath(paragraph) + .orElseGet(() -> { + if (paragraph.getStyle().isPresent()) { + warnings.add(warning("Unrecognised paragraph style: " + paragraph.getStyle().get().describe())); + } + return HtmlPath.element("p"); + }); + return mapping.wrap(children); + } + + @Override + public List visit(Run run) { + List nodes = convertChildrenToHtml(run); + if (run.isStrikethrough()) { + nodes = styleMap.getStrikethrough().orElse(HtmlPath.collapsibleElement("s")).wrap(nodes); + } + if (run.isUnderline()) { + nodes = styleMap.getUnderline().orElse(HtmlPath.EMPTY).wrap(nodes); + } + if (run.getVerticalAlignment() == VerticalAlignment.SUBSCRIPT) { + nodes = list(Html.collapsibleElement("sub", nodes)); + } + if (run.getVerticalAlignment() == VerticalAlignment.SUPERSCRIPT) { + nodes = list(Html.collapsibleElement("sup", nodes)); + } + if (run.isItalic()) { + nodes = list(Html.collapsibleElement("em", nodes)); + } + if (run.isBold()) { + nodes = list(Html.collapsibleElement("strong", nodes)); + } + HtmlPath mapping = styleMap.getRunHtmlPath(run) + .orElseGet(() -> { + if (run.getStyle().isPresent()) { + warnings.add(warning("Unrecognised run style: " + run.getStyle().get().describe())); + } + return HtmlPath.EMPTY; + }); + return mapping.wrap(nodes); + } + + @Override + public List visit(Text text) { + if (text.getValue().isEmpty()) { + return list(); + } else { + return list(Html.text(text.getValue())); + } + } + + @Override + public List visit(Tab tab) { + return list(Html.text("\t")); + } + + @Override + public List visit(LineBreak lineBreak) { + return list(Html.selfClosingElement("br")); + } + + @Override + public List visit(Table table) { + return list(Html.element("table", convertChildrenToHtml(table))); + } + + @Override + public List visit(TableRow tableRow) { + return list(Html.element("tr", convertChildrenToHtml(tableRow))); + } + + @Override + public List visit(TableCell tableCell) { + return list(Html.element("td", + MammothLists.cons(Html.FORCE_WRITE, convertChildrenToHtml(tableCell)))); + } + + @Override + public List visit(Hyperlink hyperlink) { + Map attributes = map("href", generateHref(hyperlink)); + return list(Html.collapsibleElement("a", attributes, convertChildrenToHtml(hyperlink))); + } + + private String generateHref(Hyperlink hyperlink) { + if (hyperlink.getHref().isPresent()) { + return hyperlink.getHref().get(); + } else if (hyperlink.getAnchor().isPresent()) { + return "#" + generateId(hyperlink.getAnchor().get()); + } else { + return ""; + } + } + + @Override + public List visit(Bookmark bookmark) { + return list(Html.element("a", map("id", generateId(bookmark.getName())), list(Html.FORCE_WRITE))); + } + + @Override + public List visit(NoteReference noteReference) { + noteReferences.add(noteReference); + String noteAnchor = generateNoteHtmlId(noteReference.getNoteType(), noteReference.getNoteId()); + String noteReferenceAnchor = generateNoteRefHtmlId(noteReference.getNoteType(), noteReference.getNoteId()); + return list(Html.element("sup", list( + Html.element("a", map("href", "#" + noteAnchor, "id", noteReferenceAnchor), list( + Html.text("[" + noteReferences.size() + "]")))))); + } + + @Override + public List visit(Image image) { + // TODO: custom image handlers + // TODO: handle empty content type + return image.getContentType() + .map(contentType -> { + try { + ImmutableMap.Builder attributes = ImmutableMap.builder(); + + String base64 = Base64.getEncoder().encodeToString(ByteStreams.toByteArray(image.open())); + String src = "data:" + contentType + ";base64," + base64; + attributes.put("src", src); + + image.getAltText().ifPresent(altText -> attributes.put("alt", altText)); + + return list(Html.selfClosingElement("img", attributes.build())); + } catch (IOException exception) { + warnings.add(warning(exception.getMessage())); + return MammothLists.list(); + } + }) + .orElse(list()); + } + }); + } + + private String generateNoteHtmlId(NoteType noteType, String noteId) { + return generateId(noteTypeToIdFragment(noteType) + "-" + noteId); + } + + private String generateNoteRefHtmlId(NoteType noteType, String noteId) { + return generateId(noteTypeToIdFragment(noteType) + "-ref-" + noteId); + } + + private String noteTypeToIdFragment(NoteType noteType) { + switch (noteType) { + case FOOTNOTE: + return "footnote"; + case ENDNOTE: + return "endnote"; + default: + throw new UnsupportedOperationException(); + } + } + + private String generateId(String bookmarkName) { + return idPrefix + bookmarkName; + } +} diff --git a/src/test/java/org/zwobble/mammoth/tests/DocumentConverterTests.java b/src/test/java/org/zwobble/mammoth/tests/DocumentConverterTests.java index df60d06..6a4c036 100644 --- a/src/test/java/org/zwobble/mammoth/tests/DocumentConverterTests.java +++ b/src/test/java/org/zwobble/mammoth/tests/DocumentConverterTests.java @@ -1,7 +1,7 @@ package org.zwobble.mammoth.tests; import org.junit.Test; -import org.zwobble.mammoth.internal.DocumentConverter; +import org.zwobble.mammoth.internal.DocumentToHtml; import org.zwobble.mammoth.internal.DocumentToHtmlOptions; import org.zwobble.mammoth.internal.documents.*; import org.zwobble.mammoth.internal.html.Html; @@ -42,7 +42,7 @@ public class DocumentConverterTests { public void forceWriteIsInsertedIntoParagraphIfEmptyParagraphsShouldBePreserved() { DocumentToHtmlOptions options = DocumentToHtmlOptions.DEFAULT.preserveEmptyParagraphs(); assertThat( - DocumentConverter.convertToHtml(make(a(PARAGRAPH)), options), + DocumentToHtml.convertToHtml(make(a(PARAGRAPH)), options), deepEquals(success(list(Html.element("p", list(Html.FORCE_WRITE)))))); } @@ -290,7 +290,7 @@ public class DocumentConverterTests { private List convertToHtml(Document document) { DocumentToHtmlOptions options = DocumentToHtmlOptions.DEFAULT .idPrefix("doc-42-"); - Result> result = DocumentConverter.convertToHtml(document, options); + Result> result = DocumentToHtml.convertToHtml(document, options); assertThat(result.getWarnings(), hasSize(0)); return result.getValue(); } @@ -313,6 +313,6 @@ public class DocumentConverterTests { DocumentToHtmlOptions options = DocumentToHtmlOptions.DEFAULT .idPrefix("doc-42-") .addStyleMap(styleMap); - return DocumentConverter.convertToHtml(element, options); + return DocumentToHtml.convertToHtml(element, options); } } -- cgit v1.2.3