Advantages and disadvantages of exporting word via xml:
advantage:
1. The amount of code is small, the style and content are easy to control, the printing is not deformed, and it complies with office standards;
2. Supports Linux platform and does not require office installation;
3. Fixed format document output can be realized;
4. Support adding pictures;
shortcoming:
1. You need to design the word template in advance and mark the places that need to be replaced with special marks;
2. If you want to add a picture in word, you need to add a picture as a placeholder when designing the template, and then manually edit the xml template document;
1. Use of XmlWord class (use org.w3c.dom to operate XML)
XmlWord class source code: XmlWord.txt
Template used in the sample code: 2.xml
[Note]: The office that creates the template requires version 2003 and above.
Steps for usage:
1. Create a word template that needs to be exported;
2. Create an XmlWord object;
3. If there are multiple template tags, store them in the list; store replacement values;
4. Generate word document;
[Sample code]:
XmlWord test = new XmlWord();
//1. Load template
Document doc = test.LoadXml("2.xml");
//2. Set tags. The tags stored in tagList must be consistent with the tags in the template;
List<String> tagList = new ArrayList<String>();
tagList.add("${test_name}");
tagList.add("${test_no}");
//3、设置填充标记的值,dataList中存放数据顺序与tagList存放标记顺序一致;
List<String> dataList = new ArrayList<String>();
dataList.add("----用例名");
dataList.add("----用例编号");
//4、将标记和标记值存入dataMap
test.setData(tagList, dataList);
//5、替换值
/*添加图片*/
test.replacePic(doc.getDocumentElement(), "${img}", "8.jpg", imgStr);
test.replaceTagContext(doc.getDocumentElement());
//6、写入文档
test.doc2DocFile(doc, "xmlword.doc");
2、特殊说明
1、word模板制作:
使用office 2003及以上版本写一个需要导出的word模板,然后编辑文档的样式,将需要动态填充的内容,使用特殊标记替换,如实例代码中的标记(${test_name}),最后将编辑后的word文档另存为为“Word 2003 XML 文档(*.xml)”格式,将模板放置在工程下。
2、添加图片:
如果需要在word中添加图片,在第一步制作模板时,加入一张图片占位,然后打开xml文档,可以看到如下的一片base64编码后的代码:
<w:binData w:name="wordml://03001.png" xml:space="preserve">iVBO……CC</w:binData>
只要将base64的代码替换成例如:${image},如下:
<w:binData w:name="wordml://03001.png" xml:space="preserve">${image}</w:binData>
这里要注意“>${image}<”这尖括号中间不能加任何其他的诸如空格,tab,换行等符号,否则导出的word将会出错。
3、XmlWord类说明
Properties:
变量 |
说明 |
Map<String,String> dataMap |
用于当模板中有多个标记时存放标记值及替换数据。
|
Methods:
方法 |
参数 |
返回值 |
LoadXml(String filename):Document 载入一个xml文档 |
filename:模板路径 |
成功返回Document对象; 失败返回null |
getImageStr(String imgFile):String 图片转码 |
ImgFile:图片全路径名 |
返回图片base64字符串 |
doc2DocFile(Document document,String filename):boolean 将Document对象保存为一个Doc文件 |
filename:保存的文件名 document:需要保存的Document对象 |
true:保存成功 false:保存失败 |
replaceTagContext(Element element,String tag,String data):Element 替换标识内容:单个标记(仅用于替换文本) |
element:要填充内容的节点 tag:模板中标记 data:数据 |
返回替换后的节点 |
replaceTagContext(Element element):Element 替换标识内容:多个标记,调用此方法前,先调用setData方法(仅用于替换文本) |
element:要替换内容的节点 |
返回替换后的节点 |
replacePic(Object element,String tag,String imgName,String imgStr):Element 添加图片,此方法仅适用于单张图片的添加,多图添加可参考该方法源码 |
element:要替换内容的节点 tag:模板中图片标记 imgName:图片名称,若word中有多张图,图片名必须唯一 imgStr:图片转码后的base64字符串 |
返回替换后的节点 |
本类目前仅能支持文本、图片分次替换,未实现文本同图片的同时替换。
模板:
导出后效果:
package com.hxh.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import sun.misc.BASE64Encoder;
public class XmlWord {
private Map<String,String> dataMap = new HashMap<String,String>();
public Map<String, String> getDataMap() {
return dataMap;
}
public void setDataMap(Map<String, String> dataMap) {
this.dataMap = dataMap;
}
/**
* 设置标识值
* @param tagList 标识
* @param dataList 数据
* @param dataMap
*/
public void setData(List<String> tagList,List<String> dataList){
Iterator<String> it1 = tagList.iterator();
Iterator<String> it2 = dataList.iterator();
while(it1.hasNext()){
this.dataMap.put(it1.next(), it2.next());
}
}
/**
* 载入一个xml文档
* @param filename 文件路径
* @return 成功返回Document对象,失败返回null
*/
public Document LoadXml(String filename){
Document doc = null;
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
doc = (Document) builder.parse(new File(filename));
} catch (Exception e) {
System.out.println("载入xml文件时出错");
e.printStackTrace();
}
return doc;
}
/**
* 图片转码
* @return 返回图片base64字符串
* @throws Exception
*/
public String getImageStr(String imgFile){
InputStream in = null;
BASE64Encoder encoder = null;
byte[] data = null;
try {
in = new FileInputStream(imgFile);
} catch (FileNotFoundException e) {
System.out.println("文件没找到!");
e.printStackTrace();
}
try {
data = new byte[in.available()];
in.read(data);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
encoder = new BASE64Encoder();
return encoder.encode(data);
}
/**
* doc2XmlFile
* 将Document对象保存为一个xml文件
* @return true:保存成功 flase:失败
* @param filename 保存的文件名
* @param document 需要保存的document对象
*/
public boolean doc2XmlFile(Document document,String filename)
{
boolean flag = true;
try{
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
DOMSource source=new DOMSource();
source.setNode(document);
StreamResult result=new StreamResult();
FileOutputStream fileOutputStream = new FileOutputStream(filename);
result.setOutputStream(fileOutputStream);
transformer.transform(source, result);
fileOutputStream.close();
}catch(Exception ex){
flag = false;
ex.printStackTrace();
}
return flag;
}
/**
* 替换标识内容:单个文本标记
* @param element 要替换内容的节点
* @param tag 标识名称
* @param data 替换参数
* @return 返回替换后的节点
* @throws Exception
*/
public Element replaceTagContext(Object element,String tag,String data){
Element xElement = null;
xElement = (Element) element;
NodeList tElements = xElement.getElementsByTagName("w:t");//w:t标签组
for(int i=0; i<tElements.getLength(); i++){
Element tElement = (Element)tElements.item(i);
if(tElement.getTextContent().equals(tag)){
tElement.setTextContent(data);
}
}
return xElement;
}
/**
* 替换标识内容:多个文本标记
* @param element 要替换内容的节点
* @return 返回替换后的节点
* @throws Exception
*/
public Element replaceTagContext(Element element){
Element xElement = element;
NodeList tElements = xElement.getElementsByTagName("w:t");//w:t标签组
Set<String> dataSet = this.dataMap.keySet();
Iterator<String> it = dataSet.iterator();
while(it.hasNext()){
String tag = it.next();
String data = dataMap.get(tag);
for(int i=0; i<tElements.getLength(); i++){
Element tElement = (Element)tElements.item(i);
if(tElement.getTextContent().equals(tag)){
tElement.setTextContent(data);
}
}
}
return xElement;
}
/**
* 添加图片
* @param element 需要替换内容的节点
* @param tag 标识名称
* @param imgName 图片名称,若word中有多张图,图片名必须唯一
* @param imgStr 图片转码后的base64字符串
* @return 返回替换后的节点
*/
public Element replacePic(Element element,String tag,String imgName,String imgFile){
Element xElement = element;
NodeList tElements = xElement.getElementsByTagName("w:binData");//w:t标签组 pkg:binaryData
String wName = "wordml://"+imgName;
for(int i=0; i<tElements.getLength(); i++){
Element picElement = (Element)tElements.item(i);
if(picElement.getTextContent().equals(tag)){
picElement.setTextContent(this.getImageStr(imgFile));/*图片编码*/
picElement.setAttribute("w:name",wName);//设置名字
Element imagedataElement = (Element) xElement.getElementsByTagName("v:imagedata").item(i);
imagedataElement.setAttribute("src",wName);
}
}
return xElement;
}
/**
* 插入图片
* @param parentElement 图片添加至何处
* @param imgFile 图片路径
* @param isnewLine 是否换行
* @return 返回添加图片节点后的节点
*/
public Element addPic(Element parentElement,String imgFile,boolean isnewLine){
Document parent = parentElement.getOwnerDocument();
Element p = null;
Element pict = null;
Element binData = null;
Element shape = null;
Element imagedata = null;
String src = "wordml://" + new Date().getTime();
if(isnewLine){
p = parent.createElement("w:p");
}
pict = parent.createElement("w:pict");
binData = parent.createElement("w:binData");
binData.setAttribute("w:name", src);
binData.setAttribute("xml:space", "preserve");
binData.setTextContent(this.getImageStr(imgFile));
shape = parent.createElement("v:shape");
imagedata = parent.createElement("v:imagedata");
imagedata.setAttribute("src", src);
//构造图片节点
shape.appendChild(imagedata);
pict.appendChild(binData);
pict.appendChild(shape);
if(isnewLine){
p.appendChild(pict);
parentElement.appendChild(p);
}else{
parentElement.appendChild(pict);
}
return parentElement;
}
/**
* 插入段落
* @param parentElement 待添加段落的节点
* @param data 待插入数据
* @return
*/
public Element addParagraph(Element parentElement,String data){
Document parent = parentElement.getOwnerDocument();
Element p = null;
Element r = null;
Element t = null;
p = parent.createElement("w:p");
r = parent.createElement("w:r");
t = parent.createElement("w:t");
t.setTextContent(data);
//Construct picture node
r.appendChild(t);
p.appendChild(r);
parentElement.appendChild(p);
return parentElement;
}
}