
在开发中,我们经常需要在 Excel 和 Markdown 之间转换表格数据。例如,将 Excel 中的统计结果导出为 Markdown,用于 README、技术文档或项目报告;或者将 Markdown 文档中的表格导入 Excel,以便进一步编辑、筛选和分析。对于需要批量处理或定期更新的文件,通过 Java 自动完成转换可以减少手动操作,提高处理效率。
本文将介绍如何使用 Java 实现 Excel 与 Markdown 双向转换,主要包括:
- 将 Excel 工作簿转换为 Markdown 文件
- 设置 Markdown 导出时的图片路径和超链接格式
- 将 Markdown 文件转换为 Excel 工作簿
- 提取 Markdown 文档中的多个表格,并分别保存到不同的 Excel 工作表
一、准备开发环境
本文使用 Spire.XLS for Java 处理 Excel 文件。该库支持独立读取、编辑和转换 Excel,无需安装 Microsoft Office。
Excel 与 Markdown 转换功能从 15.11.3 版本开始支持,本文使用 16.10.1 版本。
在 Maven 项目的 pom.xml 中添加以下配置:
xml
<repositories>
<repository>
<id>com.e-iceblue</id>
<name>e-iceblue</name>
<url>https://repo.e-iceblue.com/nexus/content/groups/public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.xls</artifactId>
<version>16.10.1</version>
</dependency>
</dependencies>
二、使用 Java 将 Excel 转换为 Markdown
Spire.XLS for Java 支持将 Excel 工作簿直接导出为 Markdown 文件。使用 Workbook.loadFromFile() 加载 Excel 文件后,调用 saveToFile() 方法,并将输出格式指定为 FileFormat.Markdown 即可完成转换。
实现代码:
java
import com.spire.xls.Workbook;
import com.spire.xls.FileFormat;
public class ExcelToMarkdown {
public static void main(String[] args) {
Workbook workbook = new Workbook();
try {
// 加载 Excel 文件
workbook.loadFromFile("report.xlsx");
// 导出为 Markdown
workbook.saveToFile("report.md", FileFormat.Markdown);
} finally {
workbook.dispose();
}
}
}
运行后,将生成 report.md 文件。假设原始 Excel 包含一张部门工作完成情况表,转换后的 Markdown 内容如下:
markdown
| 部门 | 负责人 | 完成率 |
| --- | --- | --- |
| 技术部 | 张明 | 92% |
| 市场部 | 李华 | 88% |
| 客服部 | 王芳 | 95% |
需要注意的是,Markdown 不支持 Excel 的公式计算、合并单元格及复杂样式。如果原始工作簿包含这些内容,建议检查导出后的数据和表格结构是否符合预期。
三、自定义 Excel 转 Markdown 的图片和超链接格式
如果 Excel 文件包含图片或超链接,除了表格数据本身,还需要考虑这些内容在 Markdown 中的保存方式。
例如,将生成的 Markdown 文件上传到 GitHub 时,通常希望图片使用相对路径,以便整个文档目录可以一起移动。对于超链接,则可以选择行内链接或引用式链接。
Spire.XLS for Java 提供了 MarkdownOptions 类,用于控制这些导出选项。
其中两个比较实用的方法是:
| 方法 | 作用 |
|---|---|
isSavePicInRelativePath(true) |
使用相对路径保存图片引用,例如  |
isSaveHyperlinkAsRef(true) |
将超链接保存为引用式 Markdown 链接 |
例如,Markdown 中的行内链接通常是:
markdown
[项目官网](https://www.example.com)
设置 isSaveHyperlinkAsRef(true) 后,可以使用类似下面的引用式格式:
markdown
[项目官网][ref1]
[ref1]: https://www.example.com
以下代码演示如何让图片使用相对路径,同时将超链接保存为行内格式:
java
import com.spire.xls.Workbook;
import com.spire.xls.MarkdownOptions;
public class ExcelToMarkdownWithOptions {
public static void main(String[] args) {
Workbook workbook = new Workbook();
try {
workbook.loadFromFile("report.xlsx");
// 配置 Markdown 导出选项
MarkdownOptions options = new MarkdownOptions();
options.isSavePicInRelativePath(true);
options.isSaveHyperlinkAsRef(false);
// 使用指定选项导出 Markdown
workbook.saveToMarkdown("report_custom.md", options);
} finally {
workbook.dispose();
}
}
}
与上一节不同,这里使用的是 saveToMarkdown() 方法,并传入 MarkdownOptions 对象。
如果希望使用引用式链接,只需将 isSaveHyperlinkAsRef(false) 改为 true。
对于需要发布到 GitHub 或静态文档网站的文件,图片相对路径通常更方便管理。不过,发布时仍需保留导出的图片资源,并确保图片与 Markdown 文件之间的相对目录结构没有变化。
四、使用 Java 将 Markdown 转换为 Excel
除了将 Excel 导出为 Markdown,有时还需要将 Markdown 文档中的表格重新导入 Excel。
将 Markdown 转换为 Excel的流程同样简单,使用 Workbook.loadFromMarkdown() 方法直接加载 Markdown 文件,再通过 saveToFile() 将其保存为 Excel。
实现代码:
java
import com.spire.xls.Workbook;
import com.spire.xls.ExcelVersion;
public class MarkdownToExcel {
public static void main(String[] args) {
Workbook workbook = new Workbook();
try {
// 加载 Markdown 文件
workbook.loadFromMarkdown("tasks.md");
// 保存为 Excel 工作簿
workbook.saveToFile(
"tasks.xlsx",
ExcelVersion.Version2016
);
} finally {
workbook.dispose();
}
}
}
假设 tasks.md 包含以下任务表格:
markdown
| 任务 | 负责人 | 状态 |
| --- | --- | --- |
| 接口开发 | 张明 | 已完成 |
| 页面优化 | 李华 | 进行中 |
| 功能测试 | 王芳 | 待开始 |
执行程序后,将生成 tasks.xlsx,可以在 Excel 中查看导入的内容,并进一步编辑或处理数据。
需要留意的是,Markdown 本身不包含 Excel 的单元格类型信息。转换后,如果需要对数字、日期等数据进行计算,建议检查单元格是否被正确识别为数值或日期,而不是普通文本。
五、提取 Markdown 中的多个表格并保存到不同的 Excel 工作表
直接使用 loadFromMarkdown() 适合整体转换文件。但在一些项目中,我们可能只需要 Markdown 文档里的表格,而不需要其他说明文字。
例如,一份销售报告按地区记录了多个表格:
markdown
# 区域销售报告
## 华东地区
| 产品 | 销量 | 销售额 |
| --- | ---: | ---: |
| 产品A | 120 | 18000 |
| 产品B | 85 | 12750 |
## 华南地区
| 产品 | 销量 | 销售额 |
| --- | ---: | ---: |
| 产品A | 96 | 14400 |
| 产品B | 110 | 16500 |
如果希望将华东、华南两个地区的数据分别写入 Excel 工作表,可以先解析 Markdown 表格,再通过 Spire.XLS for Java 创建工作表并写入数据。
下面的示例使用 Java 标准库读取 Markdown 文件,识别表头和分隔行,并将每个表格保存到独立的工作表中。
Java 实现代码
java
import com.spire.xls.Workbook;
import com.spire.xls.Worksheet;
import com.spire.xls.ExcelVersion;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class MarkdownTablesToExcel {
public static void main(String[] args) throws Exception {
// 读取 Markdown 文件
List<String> lines = Files.readAllLines(
Paths.get("report.md"), StandardCharsets.UTF_8);
Workbook workbook = new Workbook();
int tableCount = 0;
boolean inCodeBlock = false;
char fenceChar = '\0';
int fenceLength = 0;
try {
workbook.getWorksheets().clear();
for (int i = 0; i < lines.size() - 1; i++) {
String line = lines.get(i).trim();
// 跳过 Markdown 代码块
if (inCodeBlock) {
int length = countLeading(line, fenceChar);
if (length >= fenceLength
&& line.substring(length).trim().isEmpty()) {
inCodeBlock = false;
}
continue;
}
int backticks = countLeading(line, '`');
int tildes = countLeading(line, '~');
if (backticks >= 3 || tildes >= 3) {
fenceChar = backticks >= 3 ? '`' : '~';
fenceLength = Math.max(backticks, tildes);
inCodeBlock = true;
continue;
}
if (!isTableRow(line)) {
continue;
}
List<String> headers = splitCells(line);
List<String> separators =
splitCells(lines.get(i + 1).trim());
// 检查表头和分隔行
if (headers.isEmpty()
|| headers.size() != separators.size()
|| !isSeparator(separators)) {
continue;
}
// 为每个表格创建工作表
Worksheet sheet = workbook.getWorksheets()
.add("表格" + (++tableCount));
// 写入表头并设置加粗
for (int col = 0; col < headers.size(); col++) {
sheet.getCellRange(1, col + 1)
.setText(headers.get(col));
sheet.getCellRange(1, col + 1)
.getStyle().getFont().isBold(true);
}
// 写入表格数据
int row = 2;
int j = i + 2;
while (j < lines.size()
&& isTableRow(lines.get(j).trim())) {
List<String> cells =
splitCells(lines.get(j).trim());
if (cells.size() != headers.size()) {
break;
}
for (int col = 0; col < cells.size(); col++) {
sheet.getCellRange(row, col + 1)
.setText(cells.get(col));
}
row++;
j++;
}
// 自动调整列宽
sheet.getAllocatedRange().autoFitColumns();
i = j - 1;
}
if (tableCount == 0) {
System.out.println("未找到 Markdown 表格。");
return;
}
// 保存 Excel 工作簿
workbook.saveToFile(
"tables.xlsx", ExcelVersion.Version2016);
System.out.println("已提取 " + tableCount + " 个表格。");
} finally {
workbook.dispose();
}
}
// 统计行首连续出现的指定字符
private static int countLeading(String line, char marker) {
int i = 0;
while (i < line.length() && line.charAt(i) == marker) {
i++;
}
return i;
}
// 判断是否为带首尾竖线的表格行
private static boolean isTableRow(String line) {
return line.startsWith("|") && line.endsWith("|");
}
// 验证 Markdown 表格分隔行
private static boolean isSeparator(List<String> cells) {
if (cells.isEmpty()) {
return false;
}
for (String cell : cells) {
if (!cell.matches(":?-+:?")) {
return false;
}
}
return true;
}
// 拆分表格单元格
private static List<String> splitCells(String line) {
List<String> cells = new ArrayList<>();
if (!isTableRow(line)) {
return cells;
}
String content = line.substring(1, line.length() - 1);
StringBuilder cell = new StringBuilder();
for (int i = 0; i < content.length(); i++) {
char ch = content.charAt(i);
// 处理转义竖线 \|
if (ch == '\\' && i + 1 < content.length()
&& content.charAt(i + 1) == '|') {
cell.append('|');
i++;
} else if (ch == '|') {
cells.add(cell.toString().trim());
cell.setLength(0);
} else {
cell.append(ch);
}
}
cells.add(cell.toString().trim());
return cells;
}
}
实现说明
这段代码首先跳过 Markdown 代码块,然后根据表头和分隔行识别表格。例如:
text
| --- | ---: | :---: |
识别到表格后,程序通过 splitCells() 拆分各列,并使用 getWorksheets().add() 创建工作表,再通过 setText() 写入数据。最后调用 autoFitColumns() 自动调整列宽。
对于前面的地区销售报告,生成的 tables.xlsx 将包含两个工作表:
- 表格1:华东地区的产品销售数据
- 表格2:华南地区的产品销售数据
适用范围: 该示例适用于结构规则、带首尾竖线的 Markdown 表格,能够识别常见的表格分隔行、简单的转义竖线,并跳过使用反引号或波浪线围栏的普通代码块。对于复杂转义、行内代码中的竖线或嵌套结构等情况,建议使用专门的 Markdown 解析库。
此外,示例使用 setText() 写入数据,单元格内容会按文本处理。如果需要对销量、销售额等字段进行计算,可以根据数据类型使用 setNumberValue() 写入数值。
六、转换时需要注意的几个问题
1. Excel 转 Markdown 后,公式和单元格格式能否保留?
Markdown 不支持 Excel 的公式计算、条件格式及复杂单元格样式,因此转换后无法完整保留这些功能。
对于包含公式的工作簿,建议在转换前确认公式结果已更新;对于包含复杂格式的表格,则需要检查导出的 Markdown 是否符合预期。
2. 为什么转换后的 Markdown 表格显示不正常?
通常需要检查表格结构和目标 Markdown 渲染器的支持情况。
例如,Excel 中的合并单元格、多层表头或复杂排版无法直接对应标准 Markdown 表格。对于这些内容,可以先在 Excel 中整理成规则的数据区域,再执行转换。
3. Markdown 转 Excel 后,数字为什么可能无法参与计算?
如果数字被写入为文本,可能会影响 Excel 中的求和、统计或其他数值计算。
例如,使用 Spire.XLS for Java 写入单元格时,可以根据数据类型选择不同的方法:
java
// 写入文本
sheet.getCellRange("A1").setText("1200");
// 写入数值
sheet.getCellRange("A2").setNumberValue(1200);
如果后续需要计算销售额、平均值或生成图表,建议在导入数据时,根据字段类型分别写入文本、数值和日期。
总结
在 Java 项目中实现 Excel 与 Markdown 互转,可以减少人工复制表格和重新整理数据的工作量。
本文介绍了如何使用 Spire.XLS for Java 完成 Excel 与 Markdown 的双向转换,以及如何自定义图片路径和超链接的导出格式。此外,还演示了如何提取 Markdown 文档中的多个表格,并将其分别保存到 Excel 工作表中。实际开发中,可以根据需求选择直接转换整个文件,或提取指定的表格数据进行处理。