基于Java开发一个Markdown到Word文档转换工具
作者:码银
操作环境:Java8,win10,idea2024,其余依赖版本请看标题四
一、引言
在文档处理场景中,将Markdown格式的文本转换为Word文档是常见需求。Markdown因其简洁的语法广泛应用于文档编写,而Word文档在办公环境中具有更好的兼容性和格式编辑功能。本文实现的工具提供了一种便捷的方式,将Markdown内容转换为Word文档,满足不同场景下的文档使用需求。
二、MarkdownToWordConverter类的设计与实现
2.1 类结构与功能概述
MarkdownToWordConverter
类包含了将Markdown内容转换为Word文档所需的多个方法,涵盖了从Markdown到HTML的转换、HTML内容的规范化处理、安全XML读取器的创建、Word文档包的构建以及文档保存等核心步骤。
2.2 Markdown到HTML的转换
convertMarkdownToHtml
方法负责将Markdown内容转换为HTML。它使用flexmark
库中的Parser
和HtmlRenderer
,通过MutableDataSet
配置解析和渲染选项,具体实现如下:
/** * 将 Markdown 内容转换为 HTML 内容 * @param markdownContent Markdown 内容 * @return 转换后的 HTML 内容 */ private static String convertMarkdownToHtml(String markdownContent) { // 创建一个可变的数据集,用于配置解析器和渲染器的选项 MutableDataSet options = new MutableDataSet(); // 创建 Markdown 解析器和 HTML 渲染器 Parser parser = Parser.builder(options).build(); HtmlRenderer renderer = HtmlRenderer.builder(options).build(); // 解析 Markdown 内容 Document document = parser.parse(markdownContent); // 渲染为 HTML 内容 return renderer.render(document); }
2.3 HTML内容的规范化与清理
convertMarkdownToWord
方法在将Markdown转换为HTML后,使用jsoup
库对HTML内容进行规范化处理。通过设置outputSettings
,使HTML符合XML语法和XHTML转义模式,并清理多余的空行和字符,代码如下:
org.jsoup.nodes.Document jsoupDoc = Jsoup.parse(htmlContent); jsoupDoc.outputSettings().syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml); jsoupDoc.outputSettings().escapeMode(Entities.EscapeMode.xhtml); htmlContent = jsoupDoc.html(); htmlContent = htmlContent.replaceAll("(?m)^[ \t]*\r?\n", "");
这里 (?m) 是多行模式,^ 匹配每行的开头,[ \t]* 匹配 0 个或多个空格或制表符,\r?\n
匹配换行符,整个正则表达式的作用是匹配每行开头的空白字符和换行符,然后将其替换为空字符串
- jsoupDoc.outputSettings().syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml);
这行代码调用outputSettings()
方法获取jsoupDoc
的输出设置对象,然后使用syntax()
方法将输出语法设置为 XML。在 HTML 中,标签闭合规则相对宽松,比如标签可以不闭合;而在 XML 中,所有标签都必须正确闭合,像这样。通过将输出语法设置为 XML,能确保生成的 HTML 内容遵循严格的标签闭合规则。 - jsoupDoc.outputSettings().escapeMode(Entities.EscapeMode.xhtml);
这行代码同样先调用outputSettings()
方法获取输出设置对象,接着使用escapeMode()
方法将字符转义模式设置为 Entities.EscapeMode.xhtml。在 HTML 里,一些特殊字符(如 <、>、& 等)需要进行转义,否则可能会导致解析错误。将转义模式设置为 xhtml 后,Jsoup 会把这些特殊字符转换为对应的 XHTML 实体引用,例如将 < 转换为 <,> 转换为 >,& 转换为 &。
2.4 创建安全的XMLReader
为了确保XML读取的安全性,使用SAXParserFactory
创建XMLReader
,禁用DOCTYPE声明以及外部通用实体和参数实体,代码如下:
SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); factory.setFeature("http://xml.org/sax/features/external-general-entities", false); factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); XMLReader xmlReader = factory.newSAXParser().getXMLReader();
2.5 构建与保存Word文档
利用docx4j
库构建Word文档包。创建WordprocessingMLPackage
,获取MainDocumentPart
,通过XHTMLImporterImpl
将规范化后的HTML内容导入到Word文档的Body
部分,最后使用Docx4J
保存文档,代码如下:
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage(); MainDocumentPart mainDocumentPart = wordMLPackage.getMainDocumentPart(); XHTMLImporterImpl XHTMLImporter = new XHTMLImporterImpl(wordMLPackage); Body body = mainDocumentPart.getJaxbElement().getBody(); body.getContent().addAll(XHTMLImporter.convert(htmlContent, null)); Docx4J.save(wordMLPackage, new File(outputFilePath), Docx4J.FLAG_NONE);
2.6 读取Markdown文件内容
readMarkdownFromFile
方法从指定路径的文件中读取Markdown内容,使用BufferedReader
逐行读取并构建字符串,代码如下:
public static String readMarkdownFromFile(String filePath) throws IOException { StringBuilder content = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { String line; while ((line = reader.readLine()) != null) { content.append(line).append("\n"); } } return content.toString(); }
三、工具使用示例
在main
方法中,通过指定Markdown文件路径和输出Word文档路径,展示了工具的使用方法。先读取Markdown文件内容,然后调用convertMarkdownToWord
方法进行转换,并在控制台输出转换结果信息,代码如下:
public static void main(String[] args) { String markdownFilePath = "C:\\Users\\admin\\Desktop\\salaries.md"; String outputWordFilePath = "C:\\Users\\admin\\Desktop\\file.docx"; try { String markdownContent = readMarkdownFromFile(markdownFilePath); convertMarkdownToWord(markdownContent, outputWordFilePath); System.out.println("Markdown 转换为 Word 文档成功!"); } catch (Exception e) { System.err.println("转换过程中出现错误: " + e.getMessage()); e.printStackTrace(); } }
四、依赖管理
工具的实现依赖多个Java库,包括flexmark
用于Markdown解析,jsoup
用于HTML处理,docx4j
用于Word文档操作,以及日志、XML处理等相关库。在pom.xml
文件中,详细列出了各个依赖及其版本号,如下所示:
<dependencies> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.15</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>2.0.44</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.7.17</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.14.0</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.8.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>5.8.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.3.29</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>5.2.3</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.3</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> <version>5.2.3</version> </dependency> <dependency> <groupId>org.docx4j</groupId> <artifactId>docx4j-JAXB-Internal</artifactId> <version>8.3.10</version> </dependency> <dependency> <groupId>org.docx4j</groupId> <artifactId>docx4j-ImportXHTML</artifactId> <version>8.3.10</version> </dependency> <dependency> <groupId>org.jvnet.jaxb2_commons</groupId> <artifactId>jaxb2-basics</artifactId> <version>1.11.1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.36</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.36</version> </dependency> <dependency> <groupId>com.vladsch.flexmark</groupId> <artifactId>flexmark</artifactId> <version>0.60.2</version> </dependency> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.16.1</version> </dependency> </dependencies>
五、转化效果
对于文字的转化效果还是可以的。
至于代码块中的内容在word里显示不佳,但是单独把word中代码块的内容拿出来放到txt,或者其他代码块中格式确实正常的
import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import numpy as np plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False df = pd.read_csv('E:\\pycharm_workspace\\数据集\\salaries.csv')
六、完整代码
package com.example.utils; import com.vladsch.flexmark.html.HtmlRenderer; import com.vladsch.flexmark.parser.Parser; import com.vladsch.flexmark.util.ast.Document; import com.vladsch.flexmark.util.data.MutableDataSet; import org.docx4j.Docx4J; import org.docx4j.convert.in.xhtml.XHTMLImporterImpl; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; import org.docx4j.wml.Body; import org.jsoup.Jsoup; import org.jsoup.nodes.Entities; import java.io.*; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.InputSource; public class MarkdownToWordConverter { /** * 将 Markdown 内容转换为 Word 文档 * @param markdownContent Markdown 内容 * @param outputFilePath 输出的 Word 文档路径 * @throws Exception 转换过程中可能出现的异常 */ public static void convertMarkdownToWord(String markdownContent, String outputFilePath) throws Exception { // 将 Markdown 转换为 HTML String htmlContent = convertMarkdownToHtml(markdownContent); // 使用 Jsoup 规范化 HTML 内容 // 使用全限定类名 org.jsoup.nodes.Document jsoupDoc = Jsoup.parse(htmlContent); jsoupDoc.outputSettings().syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml); jsoupDoc.outputSettings().escapeMode(Entities.EscapeMode.xhtml); htmlContent = jsoupDoc.html(); // 清理多余的空行和字符 htmlContent = htmlContent.replaceAll("(?m)^[ \t]*\r?\n", ""); // 创建安全的 XMLReader SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); factory.setFeature("http://xml.org/sax/features/external-general-entities", false); factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); XMLReader xmlReader = factory.newSAXParser().getXMLReader(); // 创建 Word 文档包 WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage(); MainDocumentPart mainDocumentPart = wordMLPackage.getMainDocumentPart(); // 设置 XHTML 导入器 XHTMLImporterImpl XHTMLImporter = new XHTMLImporterImpl(wordMLPackage); // 将 HTML 内容导入到 Word 文档中 Body body = mainDocumentPart.getJaxbElement().getBody(); body.getContent().addAll(XHTMLImporter.convert(htmlContent, null)); // 保存 Word 文档 Docx4J.save(wordMLPackage, new File(outputFilePath), Docx4J.FLAG_NONE); } /** * 将 Markdown 内容转换为 HTML 内容 * @param markdownContent Markdown 内容 * @return 转换后的 HTML 内容 */ private static String convertMarkdownToHtml(String markdownContent) { MutableDataSet options = new MutableDataSet(); // 创建 Markdown 解析器和 HTML 渲染器 Parser parser = Parser.builder(options).build(); HtmlRenderer renderer = HtmlRenderer.builder(options).build(); // 解析 Markdown 内容 Document document = parser.parse(markdownContent); // 渲染为 HTML 内容 return renderer.render(document); } /** * 从文件中读取 Markdown 内容 * @param filePath Markdown 文件路径 * @return Markdown 内容 * @throws IOException 读取文件时可能出现的异常 */ public static String readMarkdownFromFile(String filePath) throws IOException { StringBuilder content = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { String line; while ((line = reader.readLine()) != null) { content.append(line).append("\n"); } } return content.toString(); } public static void main(String[] args) { String markdownFilePath = "C:\\Users\\admin\\Desktop\\salaries.md"; String outputWordFilePath = "C:\\Users\\admin\\Desktop\\file.docx"; try { // 读取 Markdown 文件内容 String markdownContent = readMarkdownFromFile(markdownFilePath); // 将 Markdown 内容转换为 Word 文档 convertMarkdownToWord(markdownContent, outputWordFilePath); System.out.println("Markdown 转换为 Word 文档成功!"); } catch (Exception e) { System.err.println("转换过程中出现错误: " + e.getMessage()); e.printStackTrace(); } } }
七、也可以顺便把html文件输出出来
package com.example.utils; import com.vladsch.flexmark.html.HtmlRenderer; import com.vladsch.flexmark.parser.Parser; import com.vladsch.flexmark.util.ast.Document; import com.vladsch.flexmark.util.data.MutableDataSet; import org.docx4j.Docx4J; import org.docx4j.convert.in.xhtml.XHTMLImporterImpl; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; import org.docx4j.wml.Body; import org.jsoup.Jsoup; import org.jsoup.nodes.Entities; import java.io.*; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.InputSource; public class MarkdownToWordConverter { /** * 将 Markdown 内容转换为 Word 文档,并输出 HTML 文件 * @param markdownContent Markdown 内容 * @param outputWordFilePath 输出的 Word 文档路径 * @param outputHtmlFilePath 输出的 HTML 文件路径 * @throws Exception 转换过程中可能出现的异常 */ public static void convertMarkdownToWord(String markdownContent, String outputWordFilePath, String outputHtmlFilePath) throws Exception { // 将 Markdown 转换为 HTML String htmlContent = convertMarkdownToHtml(markdownContent); // 使用 Jsoup 规范化 HTML 内容 org.jsoup.nodes.Document jsoupDoc = Jsoup.parse(htmlContent); jsoupDoc.outputSettings().syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml); jsoupDoc.outputSettings().escapeMode(Entities.EscapeMode.xhtml); htmlContent = jsoupDoc.html(); // 清理多余的空行和字符 htmlContent = htmlContent.replaceAll("(?m)^[ \t]*\r?\n", ""); // 输出 HTML 文件 try (FileWriter writer = new FileWriter(outputHtmlFilePath)) { writer.write(htmlContent); } // 创建安全的 XMLReader SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); factory.setFeature("http://xml.org/sax/features/external-general-entities", false); factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); XMLReader xmlReader = factory.newSAXParser().getXMLReader(); // 创建 Word 文档包 WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage(); MainDocumentPart mainDocumentPart = wordMLPackage.getMainDocumentPart(); // 设置 XHTML 导入器 XHTMLImporterImpl XHTMLImporter = new XHTMLImporterImpl(wordMLPackage); // 将 HTML 内容导入到 Word 文档中 Body body = mainDocumentPart.getJaxbElement().getBody(); body.getContent().addAll(XHTMLImporter.convert(htmlContent, null)); // 保存 Word 文档 Docx4J.save(wordMLPackage, new File(outputWordFilePath), Docx4J.FLAG_NONE); } /** * 将 Markdown 内容转换为 HTML 内容 * @param markdownContent Markdown 内容 * @return 转换后的 HTML 内容 */ private static String convertMarkdownToHtml(String markdownContent) { MutableDataSet options = new MutableDataSet(); // 创建 Markdown 解析器和 HTML 渲染器 Parser parser = Parser.builder(options).build(); HtmlRenderer renderer = HtmlRenderer.builder(options).build(); // 解析 Markdown 内容 Document document = parser.parse(markdownContent); // 渲染为 HTML 内容 return renderer.render(document); } /** * 从文件中读取 Markdown 内容 * @param filePath Markdown 文件路径 * @return Markdown 内容 * @throws IOException 读取文件时可能出现的异常 */ public static String readMarkdownFromFile(String filePath) throws IOException { StringBuilder content = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { String line; while ((line = reader.readLine()) != null) { content.append(line).append("\n"); } } return content.toString(); } public static void main(String[] args) { String markdownFilePath = "C:\\Users\\admin\\Desktop\\markdown文件\\salaries.md"; String outputWordFilePath = "C:\\Users\\admin\\Desktop\\markdown文件\\file.docx"; String outputHtmlFilePath = "C:\\Users\\admin\\Desktop\\markdown文件\\file.html"; try { // 读取 Markdown 文件内容 String markdownContent = readMarkdownFromFile(markdownFilePath); // 将 Markdown 内容转换为 Word 文档,并输出 HTML 文件 convertMarkdownToWord(markdownContent, outputWordFilePath, outputHtmlFilePath); System.out.println("Markdown 转换为 Word 文档和 HTML 文件成功!"); } catch (Exception e) { System.err.println("转换过程中出现错误: " + e.getMessage()); e.printStackTrace(); } } }
以上就是基于Java开发一个Markdown到Word文档转换工具的详细内容,更多关于Java Markdown到Word转换的资料请关注脚本之家其它相关文章!