当前位置: 首页 > article >正文

关于java实现word(docx、doc)转html的解决方案

最近在研究一些关于文档转换格式的方法,因为需要用在开发的一个项目上,所以投入了一些时间,给大家聊下这块逻辑及解决方案。

一、关于word转换html大致都有哪些方法?

(1)使用 Microsoft Word 导出

        其实该方法就是使用word本身导出方案

操作步骤

  1. 在 Microsoft Word 中打开文档。
  2. 点击 文件 > 另存为 或 导出。
  3. 选择保存类型为 网页(.html, .htm)。
  4. 保存文件后,会生成一个 HTML 文件(有时会附带一个文件夹用于存放图片等资源)。

优点

  • 保留了文档的大部分格式。
  • 操作简单,无需其他工具。

缺点

  • 导出的 HTML 文件代码较冗余,包含许多与 Word 相关的样式和标签。

(2)使用第三方工具或在线转换工具

        一般常见的有SmallPDF、Zamzar、Convertio、LibreOffice等在线工具或软件进行转换

优点

  • 方便快捷,适合大多数人使用。
  • 有些工具可以清理冗余代码,生成更简洁的 HTML。

缺点

  • 在线工具可能存在隐私和安全风险。
  • 某些工具可能无法完全保留复杂文档的格式。

(3)使用编程实现自动化转换

常见的编程实现有:

  • Python
    • 使用 python-docx 库读取 .docx 文件,再用自定义逻辑生成 HTML。
    • 使用 mammoth 库,专门将 .docx 转为干净的 HTML(推荐)。
    • 使用 pywin32 调用 Windows COM 接口操作 Microsoft Word。
  • Java
    • 使用 Apache POI 的 XWPF 模块解析 .docx 文件并输出 HTML。
  • Node.js
    • 使用 officegenmammoth.js 转换 .docx 文件。
  • C#
    • 使用 OpenXML SDK 或 Interop.Word 来操作 Word 文件并转换为 HTML。

        本此讲解的就是通过java的poi内的模块进行解析输出html

二、docx转换html

        示例代码如下:

public static void docxtoHtml(String fileName, String outPutFile) throws TransformerException, IOException, ParserConfigurationException {long startTime = System.currentTimeMillis();XWPFDocument document = new XWPFDocument(new FileInputStream(fileName));// 用于存储目录内容StringBuilder toc = new StringBuilder();toc.append("<div id='toc'>\n<ul>\n");  // 直接从 <ul> 开始,表示目录// 遍历文档中的段落,查找目录项List<XWPFParagraph> paragraphs = document.getParagraphs();int tocLevel = 0; // 目录的当前级别,1代表一级目录,2代表二级目录,3代表三级目录boolean tocStarted = false; // 标记目录是否开始for (XWPFParagraph paragraph : paragraphs) {String style = paragraph.getStyle();  // 获取段落样式String text = paragraph.getText();  // 获取段落文本// 根据段落的样式级别来识别目录项,假设标题样式为 Heading 1, Heading 2, Heading 3if (style != null) {if (style.equals("Heading 1")) {  // 一级标题if (tocStarted) {toc.append("</ul>\n"); // 关闭上一级目录}toc.append("<ul>\n");  // 开始一个新的无序列表toc.append("<li><a href='#" + text.hashCode() + "'>" + text + "</a></li>\n");tocLevel = 1;tocStarted = true;} else if (style.equals("Heading 2")) {  // 二级标题if (tocLevel == 1) {toc.append("<ul>\n");  // 开始二级目录}toc.append("<li><a href='#" + text.hashCode() + "'>" + text + "</a></li>\n");tocLevel = 2;} else if (style.equals("Heading 3")) {  // 三级标题if (tocLevel == 2) {toc.append("<ul>\n");  // 开始三级目录}toc.append("<li><a href='#" + text.hashCode() + "'>" + text + "</a></li>\n");tocLevel = 3;}}// 在目录项前插入锚点if (style != null && (style.equals("Heading 1") || style.equals("Heading 2") || style.equals("Heading 3"))) {String anchor = "<a name='" + text.hashCode() + "'></a>";String modifiedText = anchor + text;  // 在目录项文本前添加锚点// 更新段落中的文本for (XWPFRun run : paragraph.getRuns()) {run.setText(modifiedText, 0); // 更新段落内容}}}// 如果目录结束后,确保关闭所有的<ul>标签if (tocLevel > 0) {toc.append("</ul>\n");}toc.append("</ul>\n</div>\n");  // 关闭最外层的 <ul> 和 <div>// 设置XHTMLOptionsXHTMLOptions options = XHTMLOptions.create().indent(4);File imageFolder = new File(tempPath);  // 图片临时文件夹路径options.setExtractor(new FileImageExtractor(imageFolder));options.URIResolver(new FileURIResolver(imageFolder));// 使用 `XHTMLConverter` 进行 DOCX 到 HTML 的转换ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();XHTMLConverter.getInstance().convert(document, byteArrayOutputStream, options);System.out.println("Generate " + outPutFile + " with " + (System.currentTimeMillis() - startTime) + " ms.");// 获取转换后的HTML内容String htmlContent = new String(byteArrayOutputStream.toByteArray(), "UTF-8");// 将TOC插入到HTML的开头htmlContent = toc + htmlContent;// 处理分页符:将分页符添加到HTML中htmlContent = htmlContent.replaceAll("<!-- PAGE_BREAK -->", "<div class='page-break'></div>");// 添加表格样式(边框)htmlContent = htmlContent.replaceAll("<table>", "<table style='border: 1px solid black !important; border-collapse: collapse; width: 100%;'>");htmlContent = htmlContent.replaceAll("<td>", "<td style='border: 1px solid black !important; padding: 5px; text-align: left;'>");htmlContent = htmlContent.replaceAll("<th>", "<th style='border: 1px solid black !important; padding: 5px; text-align: left;'>");htmlContent = htmlContent.replaceAll("<tr>", "<tr style='border: 1px solid black !important;'>");htmlContent = htmlContent.replaceAll("<thead>", "<thead style='border: 1px solid black !important;'>");htmlContent = htmlContent.replaceAll("<tbody>", "<tbody style='border: 1px solid black !important;'>");htmlContent = htmlContent.replaceAll("<tfoot>", "<tfoot style='border: 1px solid black !important;'>");// 增加全局CSS样式(确保表格和目录样式正确)String style = "<style>\n" +"table { border: 1px solid black !important; border-collapse: collapse; width: 100%; }\n" +"td, th { border: 1px solid black !important; padding: 5px; text-align: left; }\n" +"tr { border: 1px solid black !important; }\n" +"ul { list-style-type: none; padding: 0; }\n" + // 去掉默认的列表样式"li { margin: 5px 0; }\n" + // 设置目录项的间距"</style>\n";htmlContent = style + htmlContent;// 将最终的HTML内容写入文件writeFile(htmlContent, outPutFile);
}

        该方法功能实现:

  • .docx 文件转换为 HTML 文件。
  • 自动生成基于文档标题的目录 (TOC)。
  • 为标题添加锚点链接,支持 HTML 页面内跳转。
  • 处理分页符,将其转换为 HTML 的 <div> 元素。
  • 增强表格样式,添加边框和对齐(有时原表格css样式转换后会被覆盖掉)。
  • 为 HTML 页面添加全局 CSS 样式,保证视觉效果统一。

三、doc转换html

        示例代码如下:

public static void doctoHtml(String fileName, String outPutFile) throws TransformerException, IOException, ParserConfigurationException {// 开始计时long startTime = System.currentTimeMillis();// 读取 Word 文档HWPFDocument wordDocument = new HWPFDocument(new FileInputStream(fileName));// 创建 Word 转 HTML 转换器WordToHtmlConverter wordToHtmlConverter = new WordToHtmlConverter(DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument());// 图片保存路径设置String imageFolderPath = tempPath + "images" + File.separator;  // 存储图片的绝对路径// 设置图片管理器,处理图片保存逻辑wordToHtmlConverter.setPicturesManager(new PicturesManager() {public String savePicture(byte[] content, PictureType pictureType, String suggestedName, float widthInches, float heightInches) {String picturePath = imageFolderPath + suggestedName;  // 图片保存路径File imageFolder = new File(imageFolderPath);if (!imageFolder.exists()) {boolean created = imageFolder.mkdirs(); // 创建图片文件夹if (created) {System.out.println("在以下位置创建图片文件夹:" + imageFolder.getAbsolutePath());} else {System.out.println("创建图片文件夹失败");}}try {File pictureFile = new File(picturePath);try (FileOutputStream fos = new FileOutputStream(pictureFile)) {fos.write(content);  // 写入图片数据System.out.println("图片保存路径" + pictureFile.getAbsolutePath());}} catch (IOException e) {e.printStackTrace();}return picturePath;  // 返回图片路径}});// 处理文档内容,转换为 HTMLwordToHtmlConverter.processDocument(wordDocument);// 获取生成的 HTML 文档Document htmlDocument = wordToHtmlConverter.getDocument();// 自定义分页符处理:查找文档中的分页符并插入到 HTML 中NodeList bodyNodes = htmlDocument.getElementsByTagName("body");if (bodyNodes.getLength() > 0) {Node bodyNode = bodyNodes.item(0);  // 获取 HTML 中的 <body> 节点NodeList paragraphs = bodyNode.getChildNodes();for (int i = 0; i < paragraphs.getLength(); i++) {Node paragraph = paragraphs.item(i);if (paragraph.getNodeType() == Node.ELEMENT_NODE && paragraph.getNodeName().equals("p")) {String innerText = paragraph.getTextContent();if (innerText.contains("\f")) {  // 检查是否包含分页符(\f)// 创建自定义分页符 HTML 元素Element pageBreak = htmlDocument.createElement("div");pageBreak.setAttribute("class", "page-break");  // 设置 class 属性,方便样式控制pageBreak.appendChild(htmlDocument.createTextNode(" "));// 在分页符前插入自定义分页符标记bodyNode.insertBefore(pageBreak, paragraph);}}}}// 将 HTML 文档输出为字节流ByteArrayOutputStream out = new ByteArrayOutputStream();DOMSource domSource = new DOMSource(htmlDocument);StreamResult streamResult = new StreamResult(out);// 使用 Transformer 进行 HTML 格式化输出TransformerFactory tf = TransformerFactory.newInstance();Transformer serializer = tf.newTransformer();serializer.setOutputProperty(OutputKeys.ENCODING, "utf-8");  // 设置编码为 UTF-8serializer.setOutputProperty(OutputKeys.INDENT, "yes");  // 格式化输出serializer.setOutputProperty(OutputKeys.METHOD, "html");  // 输出格式为 HTMLserializer.transform(domSource, streamResult);out.close();// 将字节流转换为字符串String htmlContent = new String(out.toByteArray());// 处理特殊标记符,例如去掉目录标记(根据需要调整)htmlContent = htmlContent.replaceAll("TOC \\\\o \"1-3\" \\\\h \\\\z \\\\u", "");// 将生成的 HTML 内容写入文件writeFile(htmlContent, outPutFile);// 输出生成文件的信息及用时System.out.println("Generate " + outPutFile + " with " + (System.currentTimeMillis() - startTime) + " ms.");
}

        该方法功能实现:

  • .doc 格式的 Word 文档转换为 HTML 文件。
  • 提取并保存文档中的图片到指定路径,并在 HTML 中插入图片引用。
  • 处理分页符,将分页符(\f)替换为自定义的 HTML 标记。
  • 格式化生成的 HTML 文件,便于阅读和使用。

相关文章:

关于java实现word(docx、doc)转html的解决方案

最近在研究一些关于文档转换格式的方法&#xff0c;因为需要用在开发的一个项目上&#xff0c;所以投入了一些时间&#xff0c;给大家聊下这块逻辑及解决方案。 一、关于word转换html大致都有哪些方法&#xff1f; &#xff08;1&#xff09;使用 Microsoft Word 导出 其实该…...

Padas进行MongoDB数据库CRUD

在数据处理的领域,MongoDB作为一款NoSQL数据库,以其灵活的文档存储结构和高扩展性广泛应用于大规模数据处理场景。Pandas作为Python的核心数据处理库,能够高效处理结构化数据。在MongoDB中,数据以JSON格式存储,这与Pandas的DataFrame结构可以很方便地互相转换。通过这篇教…...

DeepSeek-R1:强化学习驱动的推理模型

1月20日晚&#xff0c;DeepSeek正式发布了全新的推理模型DeepSeek-R1&#xff0c;引起了人工智能领域的广泛关注。该模型在数学、代码生成等高复杂度任务上表现出色&#xff0c;性能对标OpenAI的o1正式版。同时&#xff0c;DeepSeek宣布将DeepSeek-R1以及相关技术报告全面开源。…...

scratch变魔术 2024年12月scratch三级真题 中国电子学会 图形化编程 scratch三级真题和答案解析

目录 scratch变魔术 一、题目要求 1、准备工作 2、功能实现 二、案例分析 1、角色分析 2、背景分析 3、前期准备 三、解题思路 1、思路分析 2、详细过程 四、程序编写 五、考点分析 六、 推荐资料 1、入门基础 2、蓝桥杯比赛 3、考级资料 4、视频课程 5、py…...

信息学奥赛一本通 2110:【例5.1】素数环

【题目链接】 ybt 2110&#xff1a;【例5.1】素数环 【题目考点】 1. 深搜回溯 2. 质数 【解题思路】 1~n的数字构成一个环&#xff0c;要求相邻数字加和必须是质数。 该题最终输出的是一个序列&#xff0c;只不过逻辑上序列最后一个数字的下一个数字就是序列的第一个数字…...

MyBatis框架基础学习及入门案例(2)

目录 一、数据库建表(tb_user)以及添加数据。 &#xff08;1&#xff09;数据库与数据表说明。 &#xff08;2&#xff09;字段与数据说明。 二、创建模块(或工程)、导入对应所需依赖坐标。 三、编写MyBatis核心主配置文件。(解决JDBC中"硬编码"问题) &#xff08;1&…...

python学opencv|读取图像(四十六)使用cv2.bitwise_or()函数实现图像按位或运算

【0】基础定义 按位与运算&#xff1a;全1取1&#xff0c;其余取0。按位或运算&#xff1a;全0取0&#xff0c;其余取1。 【1】引言 前序学习进程中&#xff0c;已经对图像按位与计算进行了详细探究&#xff0c;相关文章链接如下&#xff1a; python学opencv|读取图像&…...

蓝桥杯省一

四个月从c&#xff0c;cpp&#xff0c;算法一起学到省一&#xff08;考研原因没参加国赛&#xff09; 有疑问可以关注私信哦 帖子后续也会持续更新&#xff0c;分享算法竞赛&#xff08;ccpc&#xff0c;天梯赛&#xff0c;蓝桥杯&#xff0c;浙大pta&#xff09;相关知识...

【ProxyBroker】用Python打破网络限制的利器

ProxyBroker 1. 什么是ProxyBroker2. ProxyBroker的功能3. ProxyBroker的优势4. ProxyBroker的使用方法5. ProxyBroker的应用场景6.结语项目地址&#xff1a; 1. 什么是ProxyBroker ProxyBroker是一个开源工具&#xff0c;它可以异步地从多个来源找到公共代理&#xff0c;并同…...

C++ 新特性实现 ThreadPool

序言 在之前我们实现过线程池&#xff0c;但是非常基础。答题思路就是实现一个安全的队列&#xff0c;再通过 ThreadPool 来管理队列和线程&#xff0c;对外提供一个接口放入需要执行的函数&#xff0c;但是这个函数是无参无返回值的。  参数的问题我们可以使用 bind 来封装&a…...

【数据结构】_以SLTPushBack(尾插)为例理解单链表的二级指针传参

目录 1. 第一版代码 2. 第二版代码 3. 第三版代码 前文已介绍无头单向不循环链表的实现&#xff0c;详见下文&#xff1a; 【数据结构】_不带头非循环单向链表-CSDN博客 但对于部分方法如尾插、头插、任意位置前插入、任意位置前删除的相关实现&#xff0c;其形参均采用了…...

本地Harbor仓库搭建流程

Harbor仓库搭建流程 本文主要介绍如何搭建harbor仓库&#xff0c;推送本地镜像供其他机器拉取构建服务 harbor文档&#xff1a;Harbor 文档 | 配置 Harbor YML 文件 - Harbor 中文 github下载离线安装包 Releases goharbor/harbor 这是harbor的GitHub下载地址&#xff0c…...

Android vendor.img中文件执行权问题

问题 Android 9、11往vendor.img增加文件&#xff0c;烧写到设备后发现增加的可执行文件没有执行权限。经过漫长查找&#xff0c;终于找到了问题的根源&#xff0c;谨以此篇献给哪些脚踏实地的人们。 根本原因 system/core/libcutils/fs_config.cpp文件&#xff0c;fs_confi…...

环境搭建--vscode

vscode官网下载合适版本 安装vscode插件 安装 MinGW 配置环境变量 把安装目录D&#xff1a;\mingw64 配置在用户的环境变量path里即可 选择用户环境变量path 点确定保存后开启cmd输入g&#xff0c;如提示no input files 则说明Mingw64 安装成功&#xff0c;如果提示g 不是内…...

30289_SC65XX功能机MMI开发笔记(ums9117)

建立窗口步骤&#xff1a; 引入图片资源 放入图片 然后跑make pprj new job8 可能会有bug,宏定义 还会有开关灯报错&#xff0c;看命令行注释掉 接着把ture改成false 然后命令行new一遍&#xff0c;编译一遍没报错后 把编译器的win文件删掉&#xff0c; 再跑一遍虚拟机命令行…...

IDEA工具下载、配置和Tomcat配置

1. IDEA工具下载、配置 1.1. IDEA工具下载 1.1.1. 下载方式一 官方地址下载 1.1.2. 下载方式二 官方地址下载&#xff1a;https://www.jetbrains.com/idea/ 1.1.3. 注册账户 官网地址&#xff1a;https://account.jetbrains.com/login 1.1.4. JetBrains官方账号注册…...

【10.2】队列-设计循环队列

一、题目 设计你的循环队列实现。 循环队列是一种线性数据结构&#xff0c;其操作表现基于 FIFO&#xff08;先进先出&#xff09;原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。 循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普…...

多人-多agent协同可能会挑战维纳的反馈

在多人-多Agent协同系统中&#xff0c;维纳的经典反馈机制将面临新的挑战&#xff0c;而协同过程中的“算计”&#xff08;策略性决策与协调&#xff09;成为实现高效协作的核心。 1、非线性与动态性 维纳的反馈理论&#xff08;尤其是在控制理论中&#xff09;通常假设系统的动…...

JS 时间格式大全(含大量示例)

在 JS 中&#xff0c;处理时间和日期是常见的需求。无论是展示当前时间、格式化日期字符串&#xff0c;还是进行时间计算&#xff0c;JavaScript 都提供了丰富的 API 来满足这些需求。本文将详细介绍如何使用 JavaScript 生成各种时间格式&#xff0c;从基础到高级&#xff0c;…...

HarmonyOS简介:应用开发的机遇、挑战和趋势

问题 更多的智能设备并没有带来更好的全场景体验 连接步骤复杂数据难以互通生态无法共享能力难以协同 主要挑战 针对不同设备上的不同操作系统&#xff0c;重复开发&#xff0c;维护多套版本 多种语言栈&#xff0c;对人员技能要求高 多种开发框架&#xff0c;不同的编程…...

区间选点(贪心)

给定 NN 个闭区间 [ai,bi][ai,bi]&#xff0c;请你在数轴上选择尽量少的点&#xff0c;使得每个区间内至少包含一个选出的点。 输出选择的点的最小数量。 位于区间端点上的点也算作区间内。 输入格式 第一行包含整数 NN&#xff0c;表示区间数。 接下来 NN 行&#xff0c;…...

深度学习|表示学习|卷积神经网络|输出维度公式|15

如是我闻&#xff1a; 在卷积和池化操作中&#xff0c;计算输出维度的公式是关键&#xff0c;它们分别可以帮助我们计算卷积操作和池化操作后的输出大小。下面分别总结公式&#xff0c;并结合解释它们的意义&#xff1a; 1. 卷积操作的输出维度公式 当我们对输入图像进行卷积时…...

Edge-TTS在广电系统中的语音合成技术的创新应用

Edge-TTS在广电系统中的语音合成技术的创新应用 作者&#xff1a;本人是一名县级融媒体中心的工程师&#xff0c;多年来一直坚持学习、提升自己。喜欢Python编程、人工智能、网络安全等多领域的技术。 摘要 随着人工智能技术的快速发展&#xff0c;文字转语音&#xff08;Te…...

2025课题推荐——USBL与DVL数据融合的实时定位系统

准确的定位技术是现代海洋探测、海洋工程和水下机器人操作的基础。超短基线&#xff08;USBL&#xff09;和多普勒速度计&#xff08;DVL&#xff09;是常用的水下定位技术&#xff0c;但单一技术难以应对复杂环境。因此&#xff0c;USBL与DVL的数据融合以构建实时定位系统&…...

RK3588平台开发系列讲解(ARM篇)ARM64底层中断处理

文章目录 一、异常级别二、异常分类2.1、同步异常2.2、异步异常三、中断向量表沉淀、分享、成长,让自己和他人都能有所收获!😄 一、异常级别 ARM64处理器确实定义了4个异常级别(Exception Levels, EL),分别是EL0到EL3。这些级别用于管理处理器的特权级别和权限,级别越高…...

MyBatis最佳实践:提升数据库交互效率的秘密武器

第一章&#xff1a;框架的概述&#xff1a; MyBatis 框架的概述&#xff1a; MyBatis 是一个优秀的基于 Java 的持久框架&#xff0c;内部对 JDBC 做了封装&#xff0c;使开发者只需要关注 SQL 语句&#xff0c;而不关注 JDBC 的代码&#xff0c;使开发变得更加的简单MyBatis 通…...

Three.js实战项目02:vue3+three.js实现汽车展厅项目

文章目录 实战项目02项目预览项目创建初始化项目模型加载与展厅灯光加载汽车模型设置灯光材质设置完整项目下载实战项目02 项目预览 完整项目效果: 项目创建 创建项目: pnpm create vue安装包: pnpm add three@0.153.0 pnpm add gsap初始化项目 修改App.js代码&#x…...

CPP-存储区域

CPP支持手动开辟和释放内存&#xff0c;所以对于内存的理解非常重要&#xff01; 在C中&#xff0c;内存存储通常可以大致分为几个区域&#xff0c;这些区域根据存储的数据类型、生命周期和作用域来划分。这些区域主要包括&#xff1a; 代码区&#xff08;Code Segment/Text S…...

1月27(信息差)

&#x1f30d;喜大普奔&#xff0c;适用于 VS Code 的 GitHub Copilot 全新免费版本正式推出&#xff0c;GitHub 全球开发者突破1.5亿 &#x1f384;Kimi深夜炸场&#xff1a;满血版多模态o1级推理模型&#xff01;OpenAI外全球首次&#xff01;Jim Fan&#xff1a;同天两款国…...

开发环境搭建-3:配置 nodejs 开发环境 (fnm+ node + pnpm)

在 WSL 环境中配置&#xff1a;WSL2 (2.3.26.0) Oracle Linux 8.7 官方镜像 node 官网&#xff1a;https://nodejs.org/zh-cn/download 点击【下载】&#xff0c;选择想要的 node 版本、操作系统、node 版本管理器、npm包管理器 根据下面代码提示依次执行对应代码即可 基本概…...