当前位置: 首页 > 工具软件 > JBooks > 使用案例 >

docx4J实现替换word中的书签(.docx)

乐正峰
2023-12-01

替换word的几种方法(查看我的上传会有jar包资源)

1,poi       HWPFDocument 类解析.doc    XWPFDocument解析.docx   楼主只用过HWPFDocument,以后问题只针对解析.doc文件。遇到过问题1.替换书签时,页眉页脚的书签,表格中的书签和主内容的文本书签不能同时存在(这句有误,页眉页脚 替换参考https://bbs.csdn.net/topics/380228730),2.获取所有书签的方法可以获取到隐藏书签,遍历时书签集合会动态丢失,报数组下标越界异常,需要遍历时将书签集合size需要实时获取。3替换书签后文档目录无法正常显示,4附带visio图的文档替换书签后有时图会丢失  5,替换复杂文档可能存在其它情况

其它参考文献:https://elim.iteye.com/blog/2031335

资源地址:https://download.csdn.net/download/qq_19865223/10916200

2,jacob   解析.doc    只能在window下使用如果服务器时其它系统,不支持

资源地址:https://download.csdn.net/download/qq_19865223/10916236

3,docx4j  解析.docx  目前使用,不存在丢失目录和visio图的情况,docx4j 依赖很多jar包

资源地址:https://download.csdn.net/download/qq_19865223/10916213

贴上代码:poi操作.doc

	/**
	 * poi操作文档(97-2003)
	 * @throws Exception
	 */
	public static String poiOPWord(){

		InputStream is =null;
		FileOutputStream out = null;
		try {
			is = new FileInputStream("C:\\Users\\cgh\\Desktop\\book.doc");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
			//获取域替换书签
			HWPFDocument doc;
			try {
				doc = new HWPFDocument(is);

				//Range range = doc.getRange();//获取域
				Bookmarks bookmarks=doc.getBookmarks();//书签集合

				int count=bookmarks.getBookmarksCount();
				for(int i=0;i<count;i++){
					Bookmark book=bookmarks.getBookmark(i);
					String bookName=book.getName();
					Range ran = new Range(book.getStart(), book.getEnd(), doc);
					if (ran.text().length() > 0){
						if(bookName.equals("name")){
							ran.replaceText("圣诞节的撒娇的数据库是的奇偶第三季度撒看见的数据库", true);//如果有值替换
						}else if(bookName.equals("daihao")){
							ran.replaceText("ssssdq111", false);//如果有值替换
						}
					}else{
						if(bookName.equals("name")){
							ran.insertBefore("设计数据上课时间附加费将发放解放军解放");		//没值就插入
						}else if(bookName.equals("daihao")){
							ran.insertBefore("daihao1110");		//没值就插入
						}
					}
					//获取变化后的长度
					int changecount = bookmarks.getBookmarksCount();
					if(changecount!=count){
						i--;
						count=changecount;
					}
				}			

				//把当前HWPFDocument写到输出流中
				out=new FileOutputStream("D:\\wordBook\\PoiBooks.doc");
				doc.write(out);
			} catch (IOException e) {
				e.printStackTrace();
			}
		closeStream(is);
		closeOutStream(out);
		return "SUCCESS";
	}

 2.jacob操作.doc

	/**
	 * jacob操作Word(97-2003)
	 */
	public static void jacobOPWord(){
		//启动word,生成一个ActivexComponent对象
		ActiveXComponent app = new ActiveXComponent("Word.Application");
		//要转换的word文件C:\Users\cgh\Desktop
		String inFile = "C:\\Users\\cgh\\Desktop\\book2.doc";
		//要保存的目标文件
		String tpFile ="D:\\wordBook\\JacobBooks.doc";
		boolean flag = true;
		boolean visible=false;
		Dispatch docs = app.getProperty("Documents").toDispatch();
		Dispatch doc = Dispatch.invoke(docs, "Open", Dispatch.Method, new Object[]{inFile, new Variant(false)}, new int[1]).toDispatch();    //打开word文件 , false可写!!  注意 Variant的值
		Dispatch activeDocument=app.getProperty("ActiveDocument").toDispatch();
		Dispatch bookMarks = app.call(doc, "Bookmarks").toDispatch();
		int bCount = Dispatch.get(bookMarks, "Count").getInt();  //获取书签数
		//将书签列表存放到list + map 结构中    
		for (int i = 1; i <= bCount; i++){       
			Map bookMark = new HashMap();   //创建Map()
			Dispatch items = Dispatch.call(bookMarks, "Item", i).toDispatch();   
			String bookMarkKey = String.valueOf(Dispatch.get(items, "Name").getString()).replaceAll("null", "");   //读取书签命名
			Dispatch range = Dispatch.get(items, "Range").toDispatch();
			String bookMarkValue = String.valueOf(Dispatch.get(range, "Text").getString()).replaceAll("null", ""); //读取书签文本
			String MarkKey=bookMarkKey;
			String MarkValue=bookMarkValue;
			//书签名并替换的内容
			if( MarkKey.equals("name"))//书签名为xm
			{
				MarkValue ="张三勿忘维持四川从封口费西嗾使市场价四大姐夫路西法学科我创建出口下降到";  //该xm书签处插入张三;
			}
			if( MarkKey.equals("daihao")){//书签名为lxdh
				MarkValue ="10086";  //在lxdh书签处插入10086
			}
			if( MarkKey.equals("****")){  //书签名自定义
				MarkValue ="*****";   //在该书签插入自定义内容
			}
			Dispatch.put(range, "Text", new Variant(MarkValue));
			//通过打印查看便于debug
			System.out.println(bookMarkValue);
			System.out.println(MarkValue);
			//保存文件
			Dispatch.invoke(doc, "SaveAs", Dispatch.Method, new Object[] {tpFile, new Variant(0)} , new int[1]);  //new Variant(),这里面的根据传入的参数不同,可以另存为不同的类型
		}
		try{
			Variant f = new Variant(false);
			Dispatch.call(doc, "Close", f);
			flag = true;
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			app.invoke("Quit", new Variant[] {});
		}
	}

 3.docx4j操作.docx

import org.docx4j.Docx4J;
import org.docx4j.TraversalUtil;
import org.docx4j.finders.RangeFinder;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.*;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
 
public class Docx4jOPWord {
 
    public static void main(String[] args) throws Exception {
 
        // 设置的标签
        ArrayList<String> bmList = new ArrayList<>();
        bmList.add("name");
        bmList.add("daihao");
 
        // 文件源目录
        String srcPath = "C:\\Users\\cgh\\Desktop\\book1.docx";
        // 目标文件目录
        String destPath = "D:\\wordBook\\Docx4jBooks.docx";
        Map<String, String> map = new HashMap<>();
        map.put("name","张三硕大的撒多撒多撒多撒大大大大的萨达");
        map.put("daihao","男");
 
        // 打开一个存在的word
        WordprocessingMLPackage wPackage = WordprocessingMLPackage.load(new FileInputStream(srcPath));
        // 作word处理
        WordprocessingMLPackage wPackage1 = replaceContentByBookmark(wPackage, map, bmList);
        wPackage1.save(new File(destPath));
        Docx4J.toPDF(wPackage1,new FileOutputStream(new File("D:\\wordBook\\Docx4jBooks.pdf")));
 
    }
 
 
    public static  WordprocessingMLPackage  replaceContentByBookmark(WordprocessingMLPackage wPackage, Map<String, String> map, ArrayList<String> bmList)  {
        try {
            // 提取正文
            MainDocumentPart main = wPackage.getMainDocumentPart();
            Document doc = main.getContents();
            Body body = doc.getBody();
 
            // 获取段落
            List<Object> paragraphs  = body.getContent();
 
            // 提取书签并获取书签的游标
            RangeFinder rt = new RangeFinder("CTBookmark", "CTMarkupRange");
            new TraversalUtil(paragraphs, rt);
 
            // 遍历书签
            for (CTBookmark bm : rt.getStarts()) {
                // 替换文本内容
                for (String bmName: bmList) {
                    if (bm.getName().equals(bmName)){
                        Tool.replaceText(bm, map.get(bm.getName()));
                    }
                }
 
//                // 替换image
//                if (bm.getName().equals("userimg")){
//                    Tool.addImage(wPackage, bm, "C:\\Users\\0253000023\\Desktop\\4.jpg");
//                }
// 
//                // 替换image
//                if (bm.getName().equals("userimg2")){
//                    Tool.addImage(wPackage, bm, "C:\\Users\\0253000023\\Desktop\\333.jpg");
//                }
            }
 
        } catch (Exception e){
            // handle exception
        }
 
        return  wPackage;
    }
 
}

 

tool类:

import org.docx4j.Docx4J;
import org.docx4j.XmlUtils;
import org.docx4j.convert.out.FOSettings;
import org.docx4j.dml.Graphic;
import org.docx4j.dml.GraphicData;
import org.docx4j.dml.picture.Pic;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFont;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
import org.docx4j.wml.*;

import javax.xml.bind.JAXBElement;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
 
/**
 * 模板word内容替换工具类
 */
public class Tool {
 
    /**
     * 在标签处插入替换内容
     *
     * @param bm
     * @param wPackage
     * @param object
     * @throws Exception
     */
    public static void replaceText(CTBookmark bm, Object object) throws Exception {
        if (object == null) {
            return;
        }
        if (bm.getName() == null){
            return;
        }
        String value = object.toString();
        try {
            List<Object> theList = null;
            ParaRPr rpr = null;
            if (bm.getParent() instanceof P) {
                PPr pprTemp = ((P) (bm.getParent())).getPPr();
                if (pprTemp == null) {
                    rpr = null;
                } else {
                    rpr = ((P) (bm.getParent())).getPPr().getRPr();
                }
                theList = ((ContentAccessor) (bm.getParent())).getContent();
            } else {
                return;
            }
            int rangeStart = -1;
            int rangeEnd = -1;
            int i = 0;
            for (Object ox : theList) {
                Object listEntry = XmlUtils.unwrap(ox);
                if (listEntry.equals(bm)) {
                    if (((CTBookmark) listEntry).getName() != null) {
                        rangeStart = i + 1;
                    }
                } else if (listEntry instanceof CTMarkupRange) {
                    if (((CTMarkupRange) listEntry).getId().equals(bm.getId())) {
                        rangeEnd = i - 1;
                        break;
                    }
                }
                i++;
            }
            int x = i - 1;
            for (int j = x; j >= rangeStart; j--) {
                theList.remove(j);
            }
 
            ObjectFactory factory = Context.getWmlObjectFactory();
            org.docx4j.wml.R run = factory.createR();
            org.docx4j.wml.Text t = factory.createText();
            t.setValue(value);
            run.getContent().add(t);
            theList.add(rangeStart, run);
        } catch (ClassCastException cce) {
 
        }
    }
 
    /**
     * 替换image
     * @param wPackage
     * @param bm
     * @param file
     */
    public static void addImage(WordprocessingMLPackage wPackage, CTBookmark bm, String file){
 
        // 新增image
        ObjectFactory factory = Context.getWmlObjectFactory();
        P p = (P) (bm.getParent());
        R run = factory.createR();
        byte[] bytes ;
        Long newCx = 0L;
        Long newCy = 0L;
        String newRelId = null;
        try {
            bytes =inputStremToBytes(new FileInputStream(file));
            BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wPackage,bytes);
            Inline newInline = imagePart.createImageInline(null, null, 0, 1, false,0);
 
            // 获取CX 、CY
            newCx = newInline.getExtent().getCx();
            newCy = newInline.getExtent().getCy();
 
            // 获取relId
            Graphic newg = newInline.getGraphic();
            GraphicData graphicdata = newg.getGraphicData();
            Object o = graphicdata.getAny().get(0);
            Pic pic = (Pic)XmlUtils.unwrap(o);
            newRelId = pic.getBlipFill().getBlip().getEmbed();
 
        } catch (Exception e) {
            e.printStackTrace();
        }
 
        // 获取模板图片的CX 、CY 、relId
        Object parent = (P) bm.getParent();
        List<Object> rList = getAllElementFromObject(parent, R.class);
        for (Object robj: rList){
            if (robj instanceof R){
                R r = (R) robj;
                List<Object> drawList = getAllElementFromObject(r, Drawing.class);
                for (Object dobj: drawList){
                    if (dobj instanceof Drawing){
                        Drawing d = (Drawing) dobj;
                        Inline inline = (Inline)d.getAnchorOrInline().get(0);
                        // 获取CX 、CY
                        Long cx = inline.getExtent().getCx();
                        Long cy = inline.getExtent().getCy();
 
                        // 获取relId
                        Graphic g = inline.getGraphic();
                        GraphicData graphicdata = g.getGraphicData();
                        Object o = graphicdata.getAny().get(0);
                        Pic pic = (Pic)XmlUtils.unwrap(o);
                        String relId = pic.getBlipFill().getBlip().getEmbed();
 
                        // 替换relId
                        pic.getBlipFill().getBlip().setEmbed(newRelId);
                        // 处理CX、CY
                        Map<String,Long> map = dealCxy(cx, cy, newCx, newCy);
 
                        // 更改cx、cy
                        inline.getExtent().setCx(map.get("setCx"));
                        inline.getExtent().setCy(map.get("setCy"));
 
                    }
                }
            }
        }
    }
 
    /**
     * 处理图片适应大小
     * @param cx
     * @param cy
     * @param newCx
     * @param newCy
     */
    public static Map<String, Long> dealCxy(Long cx, Long cy, Long newCx, Long newCy){
        Map<String, Long> map = new HashMap<>();
        Long setCx;
        Long setCy;
 
        if (newCx > cx){
            if (newCy <= cy){
                setCx = cx;
                setCy = newCy/(newCx/cx);
            } else {
                if ((newCx/cx) > (newCy/cy)){
                    setCx = cx;
                    setCy = newCy/(newCx/cx);
                } else {
                    setCy = cy;
                    setCx = newCx/(newCy/cy);
                }
            }
        } else {   // newCx < cx
            if (newCy > cy) {
                setCx = cx;
                setCy = newCy * (cx/newCx);
            } else {
                if ((cx/newCx) > (cy/newCy)) {
                    setCx = cx;
                    setCy = newCy *(cx/newCx);
                } else {
                    setCy = cy;
                    setCx = newCy * (cy/newCy);
                }
            }
        }
        map.put("setCx",setCx);
        map.put("setCy",setCy);
        return map;
    }
 
 
    /**
     * 得到指定类型的元素
     * @param obj
     * @param toSearch
     * @return
     */
    public static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) {
        List<Object> result = new ArrayList<>();
        if (obj instanceof JAXBElement)
            obj = ((JAXBElement<?>) obj).getValue();
        if (obj.getClass().equals(toSearch))
            result.add(obj);
        else if (obj instanceof ContentAccessor) {
            List<?> children = ((ContentAccessor) obj).getContent();
            for (Object child : children) {
                result.addAll(getAllElementFromObject(child, toSearch));
            }
        }
        return result;
    }
 
    /**
     * word 转换 pdf (实际是没有用到的)
     * @param docxPath
     * @param pdfPath
     * @throws Exception
     */
    public static void convertDocxToPDF(String docxPath, String pdfPath) throws Exception {
        OutputStream os = null;
        try {
            WordprocessingMLPackage mlPackage = WordprocessingMLPackage.load(new File(docxPath));
            Mapper fontMapper = new IdentityPlusMapper();
            fontMapper.put("华文行楷", PhysicalFonts.get("STXingkai"));
            fontMapper.put("华文仿宋", PhysicalFonts.get("STFangsong"));
            fontMapper.put("隶书", PhysicalFonts.get("LiSu"));
            mlPackage.setFontMapper(fontMapper);
 
            os = new java.io.FileOutputStream(pdfPath);
 
            FOSettings foSettings = Docx4J.createFOSettings();
            foSettings.setWmlPackage(mlPackage);
            Docx4J.toFO(foSettings, os, Docx4J.FLAG_EXPORT_PREFER_XSL);
 
        }catch(Exception ex){
            ex.printStackTrace();
        }finally {
        	os.flush();
        	os.close();
        }
    }
 
    /**
     * 下载PDF文件(实际是没有用到的)
     * @param wordMLPackage
     * @param os
     * @throws Exception
     */
    public  void pdfFile(WordprocessingMLPackage wordMLPackage,OutputStream os) throws Exception {
 
        String regex = null;
        Mapper fontMapper = new IdentityPlusMapper();
        wordMLPackage.setFontMapper(fontMapper);
        PhysicalFont font = PhysicalFonts.get("Arial Unicode MS");
        String directory = "D:\\upload\\pdf";
        String fileName = "OUT_ConvertInXHTMLURL.pdf";
        File f = new File(directory,fileName);
        if(f.exists()) {
            // 文件已经存在,输出文件的相关信息
            System.out.println(f.getAbsolutePath());
            System.out.println(f.getName());
            System.out.println(f.length());
        } else {
            //  先创建文件所在的目录
            f.getParentFile().mkdirs();
        }
        File file = new File(directory+"/"+fileName);
        OutputStream os34 = new java.io.FileOutputStream(file);
        Docx4J.toPDF(wordMLPackage, os34);
        os.flush();
        os.close();
        wordMLPackage = null;
    }
 
    public static byte[] inputStremToBytes(InputStream is) throws IOException{
    	//将输入流 转换为字节数组
    			byte[] buffer=new byte[1024];
    			int len=0;
    			ByteArrayOutputStream bos=new ByteArrayOutputStream();
    			while((len=is.read(buffer))!=-1){
    				bos.write(buffer,0,len);
    			}
    			bos.flush();
    			return bos.toByteArray();
    	                /**这里可以直接将字节数组new成字符窜*/
    	 
    			//Bitmap类可以直接将byte数组转换成一张图片
    }
}

 

 类似资料: