使用 Java 以程式設計方式將 Word 文件轉換為 HTML
1. 引言
文件轉換曾經複雜且小眾,如今已成為工具集、庫乃至各種程式語言原生功能的常見組成部分。
在本教學中,我們將學習如何將 Word 文件轉換為可在瀏覽器中渲染的 HTML 頁面。具體來說,我們將學習使用 Apache POI 以程式設計方式轉換文件的兩種方法。首先,我們將轉換現代的docx檔案。之後,我們將了解傳統的doc格式。通常,這種用例在企業應用程式中很常見。
2. doc和docx的區別
直到 2007 年,微軟 Word 一直使用傳統的doc格式,該格式基於二進位表示法。因此,在不同工具之間協作時,格式的互通性和保留變得更加困難。
2007 年之後,Word 改用了基於 Office Open XML 的docx格式。這種格式結構化、標準化,並且通常更容易透過程序進行處理。
因此,轉換 Word 文件需要根據文件格式的不同而採用不同的方法。為此,我們首先介紹docx ,但為了向後相容,也涵蓋了doc 。
3. Maven 依賴項
為了支援這兩種格式,我們需要 Apache POI 模組以及XDocReport提供的 XHTML 轉換器:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>5.5.1</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.poi.xwpf.converter.xhtml</artifactId>
<version>2.1.0</version>
</dependency>
轉換器還可以配置ImageManager ,以便將嵌入的圖像寫入輔助存儲,並在生成的 HTML 中引用這些圖像。
4. 轉換docx文檔
docx檔案本質上是一個包含 XML 部分的 ZIP 壓縮包。 Apache POI 將這種複雜性隱藏在XWPFDocument API 之後,從而為我們提供了一種更簡潔的方式來處理 Word 內容。
4.1. 使用 Apache POI 轉換文檔
Apache POI 使用`XWPFDocument`類別表示docx檔案。
首先,讓我們從儲存中載入文件:
public XWPFDocument loadDocxFromPath(String path) {
try {
Path file = Paths.get(path);
if (!Files.exists(file)) {
throw new FileNotFoundException("File not found: " + path);
}
XWPFDocument document = new XWPFDocument(Files.newInputStream(file));
boolean hasParagraphs = !document.getParagraphs().isEmpty();
boolean hasTables = !document.getTables().isEmpty();
if (!hasParagraphs && !hasTables) {
document.close();
throw new IllegalArgumentException("Document is empty: " + path);
}
return document;
} catch (IOException ex) {
throw new UncheckedIOException("Cannot load document: " + path, ex);
}
}
在上面的程式碼中,我們從指定路徑載入docx文件,並拒絕空文檔。
接下來,我們為產生的 HTML 設定XHTMLOptions支援XDocReport ,它ImageManager擷取的映像儲存在與最終 HTML 輸出位於同一目錄下的images目錄中:
private XHTMLOptions configureHtmlOptions(Path outputDir) {
XHTMLOptions options = XHTMLOptions.create();
options.setImageManager(new ImageManager(outputDir.toFile(), "images"));
return options;
}
現在,我們可以轉換文件並將生成的 HTML 文件保存到輸入文檔旁邊:
public void convertDocxToHtml(String docxPath) throws IOException {
Path input = Paths.get(docxPath);
String htmlFileName = input.getFileName().toString().replaceFirst("\\.[^.]+$", "") + ".html";
Path output = input.resolveSibling(htmlFileName);
try (XWPFDocument document = loadDocxFromPath(docxPath);
OutputStream out = Files.newOutputStream(output)) {
XHTMLConverter.getInstance().convert(document, out, configureHtmlOptions(output.getParent()));
}
}
接下來,我們先寫一個測試來驗證轉換結果:
@Test
void givenSimpleDocx_whenConverting_thenHtmlFileIsCreated() throws IOException {
DocxToHtml converter = new DocxToHtml();
Path docx = Paths.get(this.getClass().getResource("/sample.docx").getPath());
converter.convertDocxToHtml(docx.toString());
Path html = docx.resolveSibling("sample.html");
assertTrue(Files.exists(html));
String content = Files.lines(html, StandardCharsets.UTF_8)
.collect(Collectors.joining("\n"));
assertTrue(content.contains("<html"));
}
如我們所見,我們正在以 UTF-8 編碼讀取文件,Apache 庫也正確地保存了該文件。但可能還有其他因素需要考慮。
4.2. 處理大型文件
對於大型文檔,資源管理至關重要。使用try-with-resources功能有助於在轉換完成後立即釋放資料流和文件資料。
如有需要,可非同步執行轉換,以防止大文件阻塞請求執行緒。
4.3 處理巢狀表和複雜格式
最後,這裡我們不考慮嵌套表格和複雜的佈局。因此,輸入的 Word 文件在視覺上可能並不總是與 HTML 完全匹配。此函數最適用於常規段落、表格和基本格式,但它也存在一些限制。例如,範例docx檔案中包含一個圖表,該圖表不會在輸出文件中轉換。為了簡化操作,我們在這裡不進行轉換。
不過,在生產系統中,最好添加回歸測試,使用反映應用程式可能需要支援的佈局的真實範例文件。
5. 舊doc轉換
舊版doc格式由 POI 的 HWPF API 而非 XWPF 處理。 Apache POI 為此用例提供了WordToHtmlConverter :
public void convertDocToHtml(String docPath) throws Exception {
Path input = Paths.get(docPath);
String htmlFileName = input.getFileName().toString().replaceFirst("\\.[^.]+$", "") + ".html";
Path output = input.resolveSibling(htmlFileName);
Path imagesDir = input.resolveSibling("images");
Files.createDirectories(imagesDir);
try (InputStream in = Files.newInputStream(Paths.get(docPath));
OutputStream out = Files.newOutputStream(output)) {
HWPFDocumentCore document = WordToHtmlUtils.loadDoc(in);
Document htmlDocument = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.newDocument();
WordToHtmlConverter converter = new WordToHtmlConverter(htmlDocument);
converter.setPicturesManager((content, pictureType, suggestedName, widthInches, heightInches) -> {
Path imageFile = imagesDir.resolve(suggestedName);
try {
Files.write(imageFile, content);
} catch (IOException e) {
throw new RuntimeException(e);
}
return "images/" + suggestedName;
});
converter.processDocument(document);
Transformer transformer = TransformerFactory.newInstance()
.newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.METHOD, "html");
transformer.transform(new DOMSource(converter.getDocument()), new StreamResult(out));
}
}
雖然內部流程有所不同,但整體想法相同:載入 Word 文檔,進行轉換,然後將 HTML 寫入儲存。此外,對於doc格式,我們需要明確指定文檔的編碼。
此外,影像轉換部分還需要一些配置。
6. 結論
在本教學中,我們學習如何使用 Apache POI 將 Word 文件轉換為 HTML。
我們介紹了使用XWPFDocument和XHTMLConverter處理現代docx檔案的方法,然後介紹了使用WordToHtmlConverter處理舊式doc檔案的方法。
和往常一樣,程式碼可以在 GitHub 上找到。