java解析.docx格式文档,XWPFTable解析换行符,以及wps和office在读写.docx文档时段落结构不同的大坑
需求
从前端传来一个.docx文档,后端解析该文档里的表格,对其中的数据进行处理。
(我也不知道为什么非要解析word文档里面的表格,而不是直接传一个excel。)
实现
1.前端用的elementui-upload,把整个.docx文件传给后端。
2.后端controller接收这个文档,注意接收的格式是MultipartFile不是file,不然就报500了。
3.后端service解析这个文档:
public Map < String, Object > dealWord(MultipartFile file) throws IOException {
// 3.1 解析整个文档
XWPFDocument xwpf = new XWPFDocument(file.getInputStream());
// 3.2 从文档中获取表格的迭代器
Iterator < XWPFTable > it = xwpf.getTablesIterator();
// 3.3 遍历所有的表格,挨个解析
while (it.hasNext()) {
// 3.3.1 获取到当前的表格
XWPFTable table = it.next();
// 3.3.2 获取到行数据
List < XWPFTableRow > rows = table.getRows();
// 3.3.3 遍历每行,获取每个单元格
for (int i = 1; i < rows.size(); i++) {
XWPFTableRow row = rows.get(i);
List<XWPFTableCell> cells = row.getTableCells();
// 3.3.4 获取每个单元格里面的文字
for(int j = 0;j<cells.size();j++){
String text = cells.get(j).getText()
}
}
}
如果只需要获取每个单元格内的文字内容,不考虑换行,那么到这里就结束了。
如果需要解析单元格内的换行符,请继续往下看。
接下来介绍这里面的大坑。
坑
一开始我以为XWPFTable是不能解析到换行符的,后来觉得怎么可能,就具体看了下XWPFTable里面的数据的结构。
但是用wps和office读写过的.docx文档,解析出来的段落结构是不一样的!
不过很好做兼容。
这里顺便介绍下解析出来的结构吧!
以如下表格为例(WPS读写版本):
这个表格解析出来的数据是类似于这样的:
字段解释:
这里的runs我也不知道怎么解释...看了看官方文档也不太明白,希望有所了解的朋友可以补充。
wps和word读写过的表格,就是在runs这里发生了差异。
图中可以看到,里面的一个段落paragrah里面有一个run对象,就是单元格1.
三个段落,各自有一个run对象。
但是在office读写过的表格里,这里可能有多个run对象,也就是单元格1可能被拆成多个run对象。
可以对比着看一下:
这里的单元格1被拆解成了单元格和1两个run对象。
探究office
闲着也是闲着,探究一下office里面run对象的数量的规则吧。
推测:以数据类型分割整个段落的文字,表格是字符串文字,1是数字。
现在我们要解析的offcie读写的表格:
解析出来的结果:
对比一下:
这就有点整不明白了吧....以我有限的知识水平,不知道为什么要把3和L拆开,但又把4L%合并成一个run对象了....
解决办法
这个问题挺好解决的:
要获取单元格内的第一排内容:
获取到tableCell,获取所有的paragrahs,获取第一个paragrah,遍历获取这个paragrah里面所有的runs.
这样就同时能适配wps和office啦。
上一段代码:
public Map < String, Object > dealWord(MultipartFile file) throws IOException {
// 3.1 解析整个文档
XWPFDocument xwpf = new XWPFDocument(file.getInputStream());
// 3.2 从文档中获取表格的迭代器
Iterator < XWPFTable > it = xwpf.getTablesIterator();
// 3.3 遍历所有的表格,挨个解析
while (it.hasNext()) {
// 3.3.1 获取到当前的表格
XWPFTable table = it.next();
// 3.3.2 获取到行数据
List < XWPFTableRow > rows = table.getRows();
// 3.3.3 遍历每行,获取每个单元格
for (int i = 1; i < rows.size(); i++) {
XWPFTableRow row = rows.get(i);
List<XWPFTableCell> cells = row.getTableCells();
// 3.3.4 获取每个单元格里面的文字
for(int j = 0;j<cells.size();j++){
String text = cells.get(j).getText()
}
// 3.3.5 获取单元格里面的第一段内容
// 如果想要获取所有段的内容 用ArrayList接收一下哈 这里不演示了
for(int k = 0;k<cells.getParagraphs().size();k++){
String text = "";
// 遍历第一段里面所有的run 注意这里只get了0的段落
for(int p = 0;p<cells.getParagraphs().get(0).getRuns().size();p++){
text = text + cells.getParagraphs().get(0).getRuns().get(p);
}
System.out.prrintln("单元格第一排的内容是:"+text);
}
}
}
是很简单的一个遍历啦,很容易适配,就写到这里了噢。
posted on 2021-12-31 18:29 northwest 阅读(1372) 评论(0) 编辑 收藏 举报