Web应用Word生成
前段时间接到一个Web应用自己主动生成Word的需求,现整理了下一些关键步骤拿来分享一下。
思路:(注:这里仅仅针对WORD2003版本号。其他版本号大同小异。)
由于WORD文件内部的数据及格式等是通过XML文件的形式存储的。所以WORD文件能够非常方便的实现由DOC到XML格式的相互转换,而操作XML文件就方便的多了,这样就实现了与平台无关的各种操作。通过节点的查询、替换、删除、新增等生成Word文件。所以,依据模板生成WORD文件实质就是由用户数据替换XML文件里特殊标签,然后另存为一个DOC文件的过程。
以下列举涉及到的一些关键步骤(以介绍信为例)
第一步:依据需求制作WORD模板
新建一个DOC格式的WORD文件,依据须要填写好模板内容,设置好模板的格式。包含字体,样式,空行等等。须要填充的数据使用特殊标签(如:【※单位名称※】)预先占位。然后将新建的WORD文件另存为XML格式文件。这样, WORD模板就制作完毕了,代码例如以下:
第二步:在配置文件里配置好模板信息
新增名为template-rule.xml的配置文件,每一个template节点相应一个模板类型。每一个template中有一个taglist节点,该节点包括的全部子节点包括了模板全部将要替换、删除节点信息。节点信息包括:节点值。节点属性英文名称,中文描写叙述,字段类型,可否删除等信息。
在设置这个配置文件时候,须要注意desc属性的值必须与模板XML中的占位符一致。比方:模板XML中设置的年份这个录入项【※年※】需与template-rule.xml中的desc="年"名称相应,代码例如以下:
<? xml version="1.0" encoding="GB2312"? >
<!-- 模板定义 -->
<templates>
<!-- 说明: S-字符串; D-日期; E-金额; M-大写金额; ifEmptyDelete: T-值为空删除父节点,默觉得F -->
<template name="RECOMMEND-LETTER" desc="介绍信" templateFile="template4.xml">
<taglist remark="单值标签列表">
<tag id="1" name="ToPartment" desc="接收部门" type="S" ifEmptyDelete="T">#ToPartment</tag><!--接收部门-->
<tag id="2" name="OwnerName" desc="姓名" type="S">#OwnerName</tag><!--姓名-->
<tag id="3" name="CountNum" desc="人数" type="S">#CountNum</tag><!--人数-->
<tag id="4" name="Business" desc="内容" type="S">#Business</tag><!--内容-->
<tag id="5" name="UsefulDays" desc="有效期" type="S">#UsefulDays</tag><!--有效期-->
<tag id="6" name="Year" desc="年" type="S">#Year</tag><!--年-->
<tag id="7" name="Month" desc="月" type="S">#Month</tag><!--月-->
<tag id="8" name="Day" desc="日" type="S">#Day</tag><!--日-->
</taglist>
</template>
</templates>
第三步:编写java代码
/**
* 參数及规则
*/
public class RuleDTO {
/**
* tag名称
*/
private String parmName;
/**
* tag描写叙述
*/
private String parmDesc;
/**
* tag序号
*/
private String parmSeq;
/**
* tag值类型
*/
private String parmType;
/**
* tag參数名称
*/
private String parmRegular;
/**
* tag值
*/
private String parmValue; /**
* tag值为空删除该属性
*/
private String ifEmptyDelete; }
/**
* 描写叙述: Word模板信息
*/
public class Template { private String name;//模板名 private String desc;//模板描写叙述 private String templateFile;//模板文件 private Vector<RuleDTO> rules;//模板规则 }
public class WordBuilder { /**
* 依据模板读取替换规则
* @param templateName 模板ID
*/
@SuppressWarnings("unchecked")
public Template loadRules(Map<String, String> ruleValue) {
InputStream in = null;
Template template = new Template();
// 规则配置文件路径
String ruleFile = "template-rule.xml"; // 模板规则名称
String templateRuleName = "";
try {
templateRuleName = ruleValue.get("ruleName");
// 读取模板规则文件
in = this.getClass().getClassLoader().getResourceAsStream(ruleFile);
// 解析模板规则
SAXBuilder sb = new SAXBuilder();
Document doc = sb.build(in);
Element root = doc.getRootElement(); // 得到根元素
List<Element> templateList = root.getChildren();// 全部模板配置
Element element = null;
Vector<RuleDTO> rules = null;
for (int i = 0; i < templateList.size(); i++) {// 遍历全部模板
element = (Element) templateList.get(i);
String templateName = element.getAttributeValue("name");
if (templateRuleName.equalsIgnoreCase(templateName)) {// 查找给定的模板配置
template.setName(templateName);
template.setDesc(element.getAttributeValue("desc"));
template.setTemplateFile(element
.getAttributeValue("templateFile"));
List<Element> tagList = ((Element) element.getChildren()
.get(0)).getChildren();// tag列表
Element tag = null;
RuleDTO ruleDTO = null;
rules = new Vector<RuleDTO>();
for (int j = 0; j < tagList.size(); j++) {
tag = (Element) tagList.get(j);
ruleDTO = new RuleDTO();
ruleDTO.setParmName(tag.getAttributeValue("name"));
ruleDTO.setParmDesc("【※"
+ tag.getAttributeValue("desc") + "※】");
ruleDTO.setParmSeq(tag.getAttributeValue("id"));
ruleDTO.setParmType(tag.getAttributeValue("type"));
if ("T".equalsIgnoreCase(tag
.getAttributeValue("ifEmptyDelete"))) {// 是否可删除标记
ruleDTO.setIfEmptyDelete("T");
} else {
ruleDTO.setIfEmptyDelete("F");
}
ruleDTO.setParmRegular(tag.getText());
// 值
// 推断參数类型
String value = (String) ((Map<String, String>) ruleValue)
.get(ruleDTO.getParmRegular().replaceAll("#",
""));
ruleDTO.setParmValue(value);
rules.add(ruleDTO);
}
template.setRules(rules);
break;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return template;
} /**
* 查找父节点
*/
public Element findElement(Element currNode, String parentNodeId) {
// 节点标示为空
if (currNode == null || parentNodeId == null) {
return null;
}
Element pNode = null;
do {
pNode = currNode.getParent();
currNode = pNode;
} while (parentNodeId.equalsIgnoreCase(pNode.getName()));
return pNode;
} /**
* 生成Word文件
*/
@SuppressWarnings("unchecked")
public String build(Template template) {
InputStream in = null;
OutputStream fo = null;
// 生成文件的路径
String file = "d:\\test\\" + template.getDesc() + ".doc";
try {
// 读取模板文件
in = this.getClass().getClassLoader()
.getResourceAsStream(template.getTemplateFile());
SAXBuilder sb = new SAXBuilder();
Document doc = sb.build(in);
Element root = doc.getRootElement(); // 得到根元素
Namespace ns = root.getNamespace();// NameSpace
// word 03模板存在<wx:sect>元素
List<Element> sectList = root.getChild("body", ns).getChildren();
Element sectElement = (Element) sectList.get(0);
// <w:p>下的标签集合
List<Element> pTagList = sectElement.getChildren("p", ns);
// <w:tbl>下的标签集合
List<Element> tblTagList = sectElement.getChildren("tbl", ns);
if (pTagList != null && pTagList.size() > 0) {
changeValue4PTag(pTagList, template.getRules(), ns, null);
}
if (tblTagList != null && tblTagList.size() > 0) {
changeValue4TblTag(tblTagList, template.getRules(), ns);
}
// 写文件
XMLOutputter outp = new XMLOutputter(" ", true, "UTF-8");
fo = new FileOutputStream(file);
outp.output(doc, fo);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
in.close();
fo.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return file;
} /**
* 针对<w:body><wx:sect><w:p>这样的层级的WORD模板, 查找及替换<w:p>下的标签。
* @param pTagList :<w:p>集合
* @param rulesValue :RuleDTO集合
* @param ns :NameSpace对象
* @param trChildren :<w:tbl>的子节点<w:tr>集合
*/
@SuppressWarnings("unchecked")
private boolean changeValue4PTag(List<Element> pTagList,
Vector<RuleDTO> rulesValue, Namespace ns, List<Element> trChildren) {
Element p = null;
boolean delFlag = false;
for (int i = 0; i < pTagList.size(); i++) {
boolean delCurrNode = false;// 删除当前节点
boolean delCurrNode4TabWR = false;// 删除table中单行节点
p = (Element) pTagList.get(i);
List<Element> pChild = p.getChildren("r", ns);
for (int j = 0; pChild != null && j < pChild.size(); j++) {
Element pChildren = (Element) pChild.get(j);
Element t = pChildren.getChild("t", ns);
if (t != null) {
String text = t.getTextTrim();
if (text.indexOf("【※") != -1) {
for (int v = 0; v < rulesValue.size(); v++) {
RuleDTO dto = (RuleDTO) rulesValue.get(v);
if (text.indexOf(dto.getParmDesc().trim()) != -1) {
// 推断属性值是否为可空删除
if ("T".equals(dto.getIfEmptyDelete())
&& StringUtils.isBlank(dto
.getParmValue())) {
// 删除该节点顶级节点
text = "";
if (trChildren != null) {// 针对<w:tbl>删除该行
Element element = ((Element) p
.getParent()).getParent();
trChildren.remove(element);
delCurrNode4TabWR = true;
} else {// 针对<w:r>删除段
// pTagList.remove(p);
pTagList.remove(pChildren);
delCurrNode = true;
}
break;
} else {
text = text.replaceAll(dto.getParmDesc()
.trim(), dto.getParmValue());
}
}
}
t.setText(text);
}
if (delCurrNode4TabWR) {// <w:tbl>TABLE下的行节点已删除
delFlag = true;
break;
} else if (delCurrNode) {// <w:p>下的节点已删除
i--;
delFlag = true;
break;
}
}
}
}
return delFlag;
} /**
* 针对含有表格的WORD模板, 查找及替换<w:tbl>下的标签。
* @param tblTagList :<w:tbl>集合
* @param rulesValue :RuleDTO集合
* @param ns :NameSpace对象
*/
@SuppressWarnings("unchecked")
private void changeValue4TblTag(List<Element> tblTagList,
Vector<RuleDTO> rulesValue, Namespace ns) {
Element p = null;
for (int i = 0; tblTagList != null && i < tblTagList.size(); i++) {
p = (Element) tblTagList.get(i);
List<Element> trChildren = p.getChildren("tr", ns);
for (int j = 0; trChildren != null && j < trChildren.size(); j++) {// 循环<w:tr>
Element pChildren = (Element) trChildren.get(j);
List<Element> tcTagList = pChildren.getChildren("tc", ns);
for (int c = 0; tcTagList != null && c < tcTagList.size(); c++) {// 循环<w:tc>取<w:p>集合
Element tcChildren = (Element) tcTagList.get(c);
List<Element> pTagList = tcChildren.getChildren("p", ns);
boolean delFlag = changeValue4PTag(pTagList, rulesValue,
ns, trChildren);
if (delFlag) {// 删除行后须要改变trChildren的指针位置
j--;
}
}
}
}
} public static void main(String[] args) throws Exception {
WordBuilder word = new WordBuilder();
Map<String, String> map = new HashMap<String, String>();
//填充參数
map.put("ToPartment", "XXX公司");
map.put("OwnerName", "张三");
map.put("CountNum", "5");
map.put("Business", "例行检查");
map.put("UsefulDays", "15");
map.put("Year", "2014");
map.put("Month", "5");
map.put("Day", "13");
map.put("ruleName", "RECOMMEND-LETTER");
Template template = word.loadRules(map);
//直接打开文件
Runtime.getRuntime().exec("explorer " + word.build(template));
}
}
第四步:大功告成
几点总结及注意事项:
1. 定义的元素name必须与template_rule.xml中相应同样的name的值一致,否则须要设置转换规则。
2. 模板xml中定义的占位符【※※】中的文字必须与template_rule.xml中相应的desc同样,否则须要设置转换规则.
3. 在配置好模板XML后,须要检查<w:body>标签下的子节点是否是<wx:sect>标签(与WORD版本号有关)。假设没有,则必须加上该标签。
4. 假设要动态删除<w:p>标签节点。则这个节点的内容须要在模板中的同一行,假设不是。则能够手动调整模板XML。
5. 假设须要实现WORD自己主动换行功能(关于模板中换行的方案暂没有想到更好的)。则须要首先计算出相应模板该行的字数。然后採用空格填充来实现。
Web应用Word生成的更多相关文章
- POI生成Web版Word文件
POI生成Web版Word文件 1 通过URL的输入流实现 2 直接把Html文本写入到Word文件 所谓的使用POI生成Web版Word文件是指利用POI将Html代码插入到 ...
- web页面 验证码 生成
web页面 验证码 生成 kaptcha 是一个非常实用的验证码生成工具.有了它,你可以生成各种样式的验证码,因为它是可配置的.kaptcha工作的原理是调用 com.google.code.kapt ...
- asp.net.web如何简单生成和保存二维码图片的例子
首先,要有生成二维码图片,需要二维码生成的类库,到官网下载thoughtWorks.QRCode.dll 例子的步骤: 1.创建项目QRCodeTest1,选择asp.net.web窗体应用程序
- Aspose.Words操作word生成PDF文档
Aspose.Words操作word生成PDF文档 using Aspose.Words; using System; using System.Collections.Generic; using ...
- Web Api 自动生成帮助文档
Web Api 自动生成帮助文档 新建Web Api项目之后,会在首页有API的导航菜单,点击即可看到API帮助文档,不过很遗憾,Description 是没有内容的. 怎么办呢? 第一步: 如果 ...
- 百度Web App在线生成平台Site App体验
最近收到百度开发者中心邮件,告知之前的百度移动建站服务已经升级为Site App了,Site App顾名思义是可以创建APP的站点,之前想建立一个APP要么是自己制作,要么是选用国外的在线Web A ...
- maven项目转成web项目没有生成WebContent目录
有时候建立maven项目转成web项目没有生成WebContent目录,此时把Dynamic web module 去掉勾选,然后ok,再点开项目的properties,再选中Dynamic web ...
- WEB服务器控件对应生成的HTML标签 及最常应用事例
首先得了解WEB服务器控件对应生成的HTML标签 label----------<span/>button---------<input type="submit" ...
- 根据wsdl文件,Web工程自动生成webservice客户端调用
根据wsdl文件,Web工程自动生成webservice客户端调用 1,工具:带有webservice插件的eclips 2,步骤: (1),新建一个Web工程:WSDLTest (2),浏览器访问W ...
随机推荐
- x86、i386、i486、i586、i686和x86_64
1.386与686 i386—几乎所有的X86平台,不论是旧的pentum或者是新的pentum-IV与K7系统CPU,都可以正常工作,i指得是Intel兼容的CPU,至于386就是CPU的等级.i5 ...
- PHPUNIT 单元测试
在windows上的安装可以参考其手册 首先下载phpunit.phar文件 1. 为php的二进制可执行文件建立 一个目录,如C:\bin 2. 将C:\bin添加到系统环境变量中, 3. 打开命令 ...
- 使用 document.onreadystatechange()来判断页面加载完
document.onreadystatechange = subSomething;//当页面加载状态改变的时候执行这个方法. function subSomething() { if(docum ...
- Loader for loading embedded assemblies z
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Ref ...
- 求一字符串最长不重复字符子串的长度【Java 版】
一. 前言 最近学习有点断断续续,整理的一些知识点要么不完整,要么完全没搞懂,不好拿上台面,还是先在草稿箱躺着吧.偶尔在浏览大牛博客http://coolshell.cn的时候,发现大牛业余时间也在做 ...
- [NOIP2013]转圈游戏
题目描述 Description n 个小伙伴(编号从 0 到 n-1)围坐一圈玩游戏.按照顺时针方向给 n 个位置编号,从0 到 n-1.最初,第 0 号小伙伴在第 0 号位置,第 1 号小伙伴在第 ...
- 线性表-串:KMP模式匹配算法
一.简单模式匹配算法(略,逐字符比较即可) 二.KMP模式匹配算法 next数组:j为字符序号,从1开始. (1)当j=1时,next=0: (2)当存在前缀=后缀情况,next=相同字符数+1: ( ...
- jQuery中实现自定义方法的扩展
JQuery包装器提供了大量的方法,可以再页面中直接使用.但是,没有 任何一个库可以满足所有的需求,所以,JQuery库提供了丰富的扩展功能 .以禁用一组表单元素为例,看看怎么简单有效的在JQuery ...
- 【转】getopt分析命令行参数
(一) 在Linux中,用命令行执行可执行文件时可能会涉及到给其加入不同的参数的问题,例如: ./a.out -a1234 -b432 -c -d 程序会根据读取的参数执行相应的操作,在C语言中,这个 ...
- HW6.23
public class Solution { public static void main(String[] args) { boolean[] box = new boolean[101]; f ...