前段时间接到一个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生成的更多相关文章

  1. POI生成Web版Word文件

    POI生成Web版Word文件 1       通过URL的输入流实现 2       直接把Html文本写入到Word文件 所谓的使用POI生成Web版Word文件是指利用POI将Html代码插入到 ...

  2. web页面 验证码 生成

    web页面 验证码 生成 kaptcha 是一个非常实用的验证码生成工具.有了它,你可以生成各种样式的验证码,因为它是可配置的.kaptcha工作的原理是调用 com.google.code.kapt ...

  3. asp.net.web如何简单生成和保存二维码图片的例子

    首先,要有生成二维码图片,需要二维码生成的类库,到官网下载thoughtWorks.QRCode.dll 例子的步骤: 1.创建项目QRCodeTest1,选择asp.net.web窗体应用程序

  4. Aspose.Words操作word生成PDF文档

    Aspose.Words操作word生成PDF文档 using Aspose.Words; using System; using System.Collections.Generic; using ...

  5. Web Api 自动生成帮助文档

    Web Api 自动生成帮助文档   新建Web Api项目之后,会在首页有API的导航菜单,点击即可看到API帮助文档,不过很遗憾,Description 是没有内容的. 怎么办呢? 第一步: 如果 ...

  6. 百度Web App在线生成平台Site App体验

    最近收到百度开发者中心邮件,告知之前的百度移动建站服务已经升级为Site App了,Site  App顾名思义是可以创建APP的站点,之前想建立一个APP要么是自己制作,要么是选用国外的在线Web A ...

  7. maven项目转成web项目没有生成WebContent目录

    有时候建立maven项目转成web项目没有生成WebContent目录,此时把Dynamic web module 去掉勾选,然后ok,再点开项目的properties,再选中Dynamic web  ...

  8. WEB服务器控件对应生成的HTML标签 及最常应用事例

    首先得了解WEB服务器控件对应生成的HTML标签 label----------<span/>button---------<input type="submit" ...

  9. 根据wsdl文件,Web工程自动生成webservice客户端调用

    根据wsdl文件,Web工程自动生成webservice客户端调用 1,工具:带有webservice插件的eclips 2,步骤: (1),新建一个Web工程:WSDLTest (2),浏览器访问W ...

随机推荐

  1. poj3257

    dp,先将材料按以终点为关键字升序排 设f[i,j]为过山车到建到位置i在用了j元钱所得到的最大价值,然后 ..] of longint; f:..,..] of longint; l,n,k,m,j ...

  2. win8.1 64 安装用友T3+sql2005-64步骤

    1. 环境:win8.1 64 专业版  4G内存  .net framwork 3.5 2.初始过程及所需软件 安装sql2008数据库,安装完T3发现并不支持此数据库,运行T3老是出现连接数据时的 ...

  3. Application Pool Identities

    Whether you are running your site on your own server or in the cloud, security must be at the top of ...

  4. C++ 学习资料搜寻与学习(第一期)(未完待续)

    一.图形图像类 [Visual C++]vs2008/2005正确打开vs2010所创建项目的几种方法 jlins 2012-04-12 14:38 [Visual C++]关于无法打开包括文件:“S ...

  5. 关于C#中static静态变量

    C#静态变量使用static 修饰符进行声明,在类被实例化时创建,通过类进行访问不带有 static 修饰符声明的变量称做非静态变量,在对象被实例化时创建,通过对象进行访问一个类的所有实例的同一C#静 ...

  6. [Bhatia.Matrix Analysis.Solutions to Exercises and Problems]ExI.5.7

    Prove that for any vectors $$\bex u_1,\cdots,u_k,\quad v_1,\cdots,v_k, \eex$$ we have $$\bex |\det(\ ...

  7. 《深入Java虚拟机学习笔记》- 第19章 方法的调用与返回

    <深入Java虚拟机学习笔记>- 第19章 方法的调用与返回

  8. HDU4614 Vases and Flowers 二分+线段树

    分析:感觉一看就是二分+线段树,没啥好想的,唯一注意,当开始摆花时,注意和最多能放的比大小 #include<iostream> #include<cmath> #includ ...

  9. JSFのAjaxタグのoneventでbegin/complete/successを使う

    PrimeFacesに慣れてしまって.通常のHTMLタグでの記述方法がわからなかったりする点があった…ので.メモ. Ajaxでリクエスト送信のタイミングやレスポンスが戻るタイミングに何らか(JavaS ...

  10. 利用doxygen提高源代码阅读效率

    阅读开源项目的源代码是提高自己编程能力的好方法,而有一个好的源代码阅读工具无疑能够让你在阅读源代码时事半功倍.之前找过不少源代码阅读工具,像SourceInsight.sourcenav.scitoo ...