转换工具我选OpenOffice (版本4)+ jodconverter(版本3)。跨平台,完全免费。
这两样工具网上很容易下载到,转换代码也很简单。主要的工作是对转换形成的html代码进行加工。主要目的有二:
1.修正失真
2.清理掉冗余代码
处理html文本主要工具是正则表达式。不过正则也有局限,比如匹配标签对。网上找到一个匹配标签对的正则,复杂的让人抓狂。因此我写一个匹配标签对的类,它的功能可示例如下:
原文本:"<a><a></a><b><a></a></b><c></c></a>"
对标签a进行匹配后:"<a1><a2></a-2><b><a3></a-3></b><c></c></a-1>"
package office;
import java.util.List;
import tools.EasyRegex;
/*
* 配对原理:一对标签之间嵌套的子标签,其开始标志数量和结束标志数量相等
*/
/**
* 配对text文本中查找到的第一对tag标签,开始标志加id,结束标志加-id
* 比如把<a></a> 标识为<a1></a-1>
* @author IBM
*/
public class TagPair {
int id = 0;
String tag;
public String result = "";
/**
* @param text
* @param tag 标签名,使用小写
* @return
*/
public TagPair(String text,String tag,int id)
{
this.id = id;
this.tag = tag;
String re = text;
int e =0;
int s = 0;
int i = re.indexOf(tag);
while(i>=0){
if(re.indexOf("<", i-1) == i-1){
s++;
if(s == 1){//indexOf大小写敏感特性这里正好为我所有,将标志过的标签转为大写,这样下次indexOf就不会再把它列入查找结果
re = re.substring(0, i) + tag.toUpperCase()+ String.valueOf(id) + re.substring(i+tag.length());
}
}
else if(re.indexOf("</", i-2) == i-2){
e++;
if(e == s){
result = re.substring(0, i) + tag.toUpperCase()+ String.valueOf(id*-1) + re.substring(i+tag.length());
break;
}
}
i = re.indexOf(tag,i+tag.length());
}
}
/**
* tag使用小写
* @param text
* @param tag
* @return
*/
public static String pair(String text,String tag)
{
//String re = toLowercase(text);//如果能保证标签都是小写形式可省略此步骤
String re = text;
int id = 1;
TagPair tp = new TagPair(re,tag,id);
while(tp.result.length() > 0){
re = tp.result;
tp = new TagPair(tp.result,tag,++id);
}
return re;
}
/**
* 大小写不敏感
* @param html
* @return
*/
public static String unPair(String html)
{
String re = html.replaceAll("(</?[a-gA-Gi-zI-Z]{1,8})(-?\\d{1,5})([^>]*?>)", "$1$3");
return re;
}
public static String toLowercase(String html)
{
String re = html;
EasyRegex reg = new EasyRegex("<[^>]+?>");
List<String> ms = reg.matchs(re);
for(String t : ms){
re = re.replace(t, t.toLowerCase());
}
return re;
}
}
OpenOffice (版本4)+ jodconverter(版本3)转换代码:
package office;
import java.io.File;
import java.util.List;
import org.artofsolving.jodconverter.OfficeDocumentConverter;
import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration;
import org.artofsolving.jodconverter.office.OfficeManager;
import tools.EasyFile;
import tools.EasyRegex;
public class Office2html {
/**
* 把office文件转换成html
* @param file office文件完整路径
* @param folder html文件及其包含资源存放路径
* @return 返回html纯文本内容
*/
public static String convert(String file)
{
OfficeManager officeManager = null;
try{
EasyFile f = new EasyFile(file);//这是我的一个工具类,对File进行了一下再包装,可用File类代替
if(f.isExists()){
String output = f.getFolder() +"/"+f.nameWithoutExt() +".html";
DefaultOfficeManagerConfiguration config = new DefaultOfficeManagerConfiguration();
config.setOfficeHome("C:\\Program Files\\OpenOffice 4");
officeManager = config.buildOfficeManager();
officeManager.start();
OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager);
File outputFile = new File(output);
converter.convert(f.getFile(), outputFile);//转换
String temp = EasyFile.readAllText(output, "GBK");
EasyFile.writeAllText(output, clearFormat(f.fileExt(),temp));
}
return "";
}
catch(Exception e){
e.printStackTrace();
return "";
}
finally{
if (officeManager != null) {
officeManager.stop();
}
}
}
/**
* ext表示转换前文件类型扩展名
* @param ext
* @param html
* @return
*/
static String clearFormat(String ext,String html)
{
String content = html;
try{
if(ext.equals("doc") || ext.equals("docx")){
//去除多余span标签
content = content.replaceAll("</?SPAN[^>]*?>", "");
content = content.replaceAll("<META[^>]+?charset=[^>]+?>", //设定网页编码
"<HEAD>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />");
//设置内容宽度并居中(接近A4纸宽度)
content = content.replaceAll("<BODY[^>]*?>", "$0\n<div style=\"width:800px;margin:0 auto;\">");
content = content.replaceAll("</BODY>", "</div>\n</BODY>");
content = content.replaceFirst("<BODY", "<BODY style=\"text-align:center;\" ");
//让图片者水平居中
content = content.replaceAll("<IMG([^>]+)ALIGN=[A-Z]{3,6}", "<IMG$1");
content = content.replaceAll("<IMG[^>]+?>", "<div align=\"center\">$0</div>");
//下面是找出所有带align属性的p标签,改为div(对齐属性在P标签里无效果)。不能把P全变成div,那样失真严重。
content = TagPair.toLowercase(content);
content = TagPair.pair(content, "p");
EasyRegex reg = new EasyRegex("(?<=<p)\\d{1,5}(?=.+align=)",true);
List<String> ls = reg.matchs(content);
for(String s : ls){
content = content.replaceFirst("<P"+s, "<div");
content = content.replaceFirst("</P-"+s, "</div");
}
content = TagPair.unPair(content);
content = content.replaceAll("line-height: 100%", ""); //这个属性败事有余,取消掉
}
else{
EasyRegex reg = new EasyRegex("<META[^>]+?charset=[^>]+?>");
content = content.replaceFirst(reg.match(content),
"<HEAD>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />");
//excel中不设边框依然有浅灰色线,但生成html就啥也没有显得太苍白,所以刻意加上。
if(content.indexOf("border-top:") < 0 && content.indexOf("border-left:")<0){
reg = new EasyRegex("<TABLE[^>]+?>");
content = content.replaceFirst(reg.match(content),//
"<TABLE border=\"1\" bordercolor=\"#a0c6e5\" style=\"border-collapse:collapse;\">");
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
return content;
}
}
注:word中的图片会被放到和html同位置文件夹下
经过这一番处理,生成的html文件凑和着能看了。但毕竟word和浏览器是不同的软件,对代码的解析有很多不一样地方。比如有的文本在word中显示居中,生成html就没这个效果了。这不是java转换的问题,是因为那段文本其实本就没有居中属性,word只是根据其上下文环境,把它给居中显示了,但浏览器显然没这样功能。
至于表格,由于其本身格式就比较固定,所以在html下表现出来和excel中差别不大。不过我也发现了一个bug,就是在转换一个较大的excel文件时,本来某单元格中只有一句话,结果转换出来后,此格中这句话重复了数十遍,这应该是openoffice或jodconverter的bug。
欢迎大家一起探讨、进步!