POI解析Word2007(.docx)跨行跨列并生成HTML内容标签

POI解析Word2007(.docx)并生成HTML内容标签

前言

查阅一些资料后,经过不断地尝试和终于弄出想要的结果了。一些内容好多帖子都一样,实在看不出谁是原创,对于内容也给了一些灵感吧,那些都是实现读取之后又在转入另一个Word中,或者直接就把字符串内容拿出来。要么没有直接看到内容,要么与原Word中表格差异太大。
简单的读取就不阐述了,下面说一下我的吧,主要是读出来生成相应的<table></table>标签,便于使用和展示。但是并没有读取表格的详细样式配置。实际只需要读取内容以及单元格的跨行跨列即可。

一、原理

首先docdocx是现实不一样的,因此在读取的时候需要分开写。在**Word2007(.docx)**文档中的解析中,先是将文档当做.zip的压缩文件解压处理,其中包含一些.xml文件,其中就包含了文档中的内容以及样式参数。跨行跨列的xml信息获取方式不同。

1.1 跨行getVMerge

以下是我举得一个例子,是一个单元格的信息,其中w:val="restart" 表示此单元格为跨行信息。一般单元格不存在跨行时无此xml信息,对象为null。存在此xml信息并且存在w:val="restart"信息时为跨行首行,若存在此xml信息但并没有w:val="restart"信息时为跨行非首行。根据此信息加上自己的处理即可

<xml-fragment w:val="restart" 
xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas"
xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" 
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
xmlns:o="urn:schemas-microsoft-com:office:office" 
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" 
xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" 
xmlns:v="urn:schemas-microsoft-com:vml" 
xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" 
xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" 
xmlns:w10="urn:schemas-microsoft-com:office:word" 
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" 
xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" 
xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" 
xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" 
xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" 
xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" 
xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" 
xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"
/>

1.2 跨列getGridSpan

对于跨列相对容易,w:val="2"这个值就说跨两列。不存在垮列时则无此xml信息。

<xml-fragment w:val="2" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"/>

二、实现

以下代码只是实例,实际不可能只有docx还会涉及doc、PDF、WPS等多种文档。写好接口做好不同实现就好。我的方法并不是最好的,只是根据想法先实现了出来,测试了不同复杂表格均可以表现出来。逻辑也都注释了,一目了然,代码直接用就可以。POI的jar就不多说了。

import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDecimalNumber;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;

import java.io.FileInputStream;
import java.util.List;

/*
 * 使用POI库对word进行处理的工具类
 */
public class DocxPOIUtils {
	public static void main(String[] args) throws Exception {
		String sourceFile = "D:\\JetBrains\\Cloud\\测试表格.docx";
		getAllTable2(sourceFile);
	}
	public static void getAllTable2(String sourceFile){
		
		try{
			XWPFDocument docx = new XWPFDocument(new FileInputStream(sourceFile));
			List<XWPFTable> tables = docx.getTables();
			List<XWPFTableRow> rows;
			List<XWPFTableCell> cells;
			for (XWPFTable table : tables) {
				
				
				String str = "";
				str += "<table border='1px solid black' cellspacing='0'>";
				// 获取表格对应的行
				rows = table.getRows();
				for (int i = 0; i < rows.size(); i++) {
					System.out.println("row---"+i);
					str += "<tr>";
					// 获取行对应的单元格
					cells = rows.get(i).getTableCells();
					for (int j = 0; j < cells.size(); j++) {
						System.out.println("cell---"+j);
						CTVMerge rowspan = cells.get(j).getCTTc().getTcPr().getVMerge();//跨行
						//------------------
						int d = 1;//跨行行数//计算是从跨行下一行开始统计的,故加上首行
						if (rowspan != null) {//rowspan存在未有跨行信息
							//跨行的第一行为restart,其他行为null
							STMerge.Enum enum1 = rowspan.getVal();
							if (enum1 != null && "restart".equals(enum1.toString())){//发现跨行信息为第一行时进行计算行数,非跨行首行则绕过不处理,已经计算在内

								for (int k = i+1; k < rows.size(); k++) {//从当前单元格的跨行首行开始遍历,避免不必要的计算
									if (rows.get(k).getTableCells().size() > j){
										CTVMerge mer = rows.get(k).getTableCells().get(j).getCTTc().getTcPr().getVMerge();
										if (mer != null) {//只要不为null就是存在连续的跨行
											STMerge.Enum enum2 = mer.getVal();
											if (enum2 != null && "restart".equals(enum2.toString())) {//若再次遇到restart,为下一次跨行,终止此次
												break;
											}else {//只要不是restart就加计算
												d++;
											}
										}else {//连续中断,出现null则为此单元格跨行结束
											break;
										}
									}else {
										d++;
									}
								}
							}
						}
						//------------------
						CTDecimalNumber colspan = cells.get(j).getCTTc().getTcPr().getGridSpan();//跨列
						if (colspan != null && rowspan != null) {
							STMerge.Enum enum1 = rowspan.getVal();
							if (enum1 != null) {
								str += "<td colspan='"+colspan.getVal()+"' rowspan='"+d+"'>";
							}
						}else if (colspan == null && rowspan != null) {
							STMerge.Enum enum1 = rowspan.getVal();
							if (enum1 != null) {
								str += "<td rowspan='"+d+"'>";
							}
						}else if (colspan != null && rowspan == null) {
							str += "<td colspan='"+colspan.getVal()+"'>";
						}else if (colspan == null && rowspan == null) {
							str += "<td>";
						}
						str += cells.get(j).getText().trim().replaceAll("[\r\n]", "").toLowerCase();
						str += "</td>";
					}
					str += "</tr>";
				}
				str += "</table>";
				System.out.println(str);
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
	}

}

产出效果为标签字符串。有个问题就是标签样式,我并没有获取详细的样式

<table border='1px solid black' cellspacing='0'><tr><td colspan='3' rowspan='2'>跨行跨列</td><td>a</td><td colspan='20'>a课题</td></tr><tr></td><td colspan='7'></td><td colspan='5'>不规则位置跨列</td><td colspan='9'></td></tr><tr><td colspan='3' rowspan='2'>紧随跨行跨列</td><td colspan='3'></td><td colspan='3'>性别</td><td></td><td colspan='4'>民族</td><td colspan='2'></td><td colspan='5'>中间跨列1</td><td colspan='3'>年  月</td></tr><tr></td><td colspan='3'></td><td colspan='4'>职务</td><td colspan='6'></td><td colspan='5'>中间跨列2</td><td colspan='3'></td></tr><tr><td colspan='3'>跨列4</td><td colspan='3'></td><td colspan='4'>学位</td><td colspan='6'></td><td colspan='5'>中间跨列3</td><td colspan='3'></td></tr><tr><td colspan='3'>跨列5</td><td colspan='10'>不规则位置跨列</td><td colspan='6'>联系电话</td><td colspan='5'></td></tr><tr><td colspan='3'>跨列6</td><td colspan='17'></td><td colspan='2'>邮编</td><td colspan='2'></td></tr><tr><td colspan='3'>跨列7</td><td colspan='4'></td><td colspan='4'>职务</td><td colspan='2'></td><td colspan='5'>工作单位</td><td colspan='6'></td></tr><tr><td colspan='3'>跨列8</td><td colspan='4'></td><td colspan='4'>职务</td><td colspan='2'></td><td colspan='5'>工作单位</td><td colspan='6'></td></tr><tr><td colspan='2'>跨列9</td><td></td><td></td><td colspan='16'>a.专著b.译著c.工具书</td><td colspan='3'>字数</td><td>万字</td></tr><tr><td colspan='5'>跨列</td><td colspan='7'></td><td colspan='7'>时间</td><td colspan='5'>年  月  日</td></tr><tr><td rowspan='3'>同列隔行跨行</td><td colspan='2'>标题1</td><td>标题2</td><td colspan='4'>标题3</td><td colspan='3'>标题4</td><td colspan='3'>标题5</td><td colspan='3'>标题6</td><td colspan='3'>标题7</td><td colspan='4'>标题8</td></tr><tr></td><td colspan='2'></td><td></td><td colspan='4'></td><td colspan='3'></td><td colspan='3'></td><td colspan='3'></td><td colspan='3'></td><td colspan='4'></td></tr><tr></td><td colspan='2'></td><td></td><td colspan='4'></td><td colspan='3'></td><td colspan='3'></td><td colspan='3'></td><td colspan='3'></td><td colspan='4'></td></tr></table>

三、效果展示

3.1Word内表格截图

在这里插入图片描述
在这里插入图片描述

3.2 HTML效果

在这里插入图片描述

四、总结

重点在于内容不再展示,因此表格边框字体等相关样式并未读取。有需要的伙伴可以自己研究一下。关于**Word2003(.doc)**文档,因为实现不同,也并没有看到好的POI接口,还不能很好地实现。后续有结果还会在发布,有相关经验的伙伴或有啥问题欢迎留言啊。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值