当前位置: 首页 > 知识库问答 >
问题:

docx4j-如何用值替换占位符

赵禄
2023-03-14

我一直在尝试通过FieldMailMerge和VariableReplace示例,但似乎无法运行本地测试用例。我基本上试图从一个docx模板文档开始,并让它从一个模板创建x个docx文档,替换变量。

在下面的代码中,docx4jReplacesImpleTest()试图替换单个变量,但失败了。模板文件中的${}值作为处理的一部分被移除,因此我认为它正在查找它们,而不是出于某种原因替换它们。我明白这可能是由于格式问题,正如示例代码的注释中所解释的那样,但对于故障排除,只是为了让一些东西正常工作,我无论如何都在尝试它。

public static void main(String[] args) throws Exception
{
    docx4jReplaceTwoPeopleTest();
    docx4jReplaceSimpleTest();
}

private static void docx4jReplaceTwoPeopleTest() throws Exception
{
      String docxFile = "C:/temp/template.docx";

      WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File(docxFile));

      List<Map<DataFieldName, String>> data = new ArrayList<Map<DataFieldName, String>>();

      Map<DataFieldName, String> map1 = new HashMap<DataFieldName, String>();
      map1.put(new DataFieldName("Person.Firstname"), "myFirstname");
      map1.put(new DataFieldName("Person.Lastname"), "myLastname");
      data.add(map1);

      Map<DataFieldName, String> map2 = new HashMap<DataFieldName, String>();
      map2.put(new DataFieldName("Person.Firstname"), "myFriendsFirstname");
      map2.put(new DataFieldName("Person.Lastname"), "myFriendsLastname");
      data.add(map2);

      org.docx4j.model.fields.merge.MailMerger.setMERGEFIELDInOutput(OutputField.KEEP_MERGEFIELD);

      int x=0;
      for(Map<DataFieldName, String> docMapping: data) 
      {
        org.docx4j.model.fields.merge.MailMerger.performMerge(wordMLPackage, docMapping, true);
        wordMLPackage.save(new java.io.File("C:/temp/OUT__MAIL_MERGE_" + x++ + ".docx") );
      }
}

private static void docx4jReplaceSimpleTest() throws Exception
{
      String docxFile = "C:/temp/template.docx";

      WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File(docxFile));

      HashMap<String, String> mappings = new HashMap<String, String>();
      mappings.put("Person.Firstname", "myFirstname");
      mappings.put("Person.Lastname", "myLastname");

      MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
      documentPart.variableReplace(mappings);

    wordMLPackage.save(new java.io.File("C:/temp/OUT_SIMPLE.docx") );
}
This is a letter to someone
Hi ${Person.Firstname} ${Person.Lastname},
How are you?
Thank you again. I wish to see you soon ${Person.Firstname}
Regards,
Someone

请注意,我还尝试将person.firstname替换至少两次。因为最后一个名字甚至没有被替换,我不认为这与它有任何关系,但我添加它只是以防万一。

共有1个答案

傅峰
2023-03-14

我也有同样的问题,当然我不能强迫用户在编写word文档时做一些额外的事情,所以我决定只写一个algo来扫描整个文档,寻找一次又一次地添加表达式、插入替换值和在第二次运行中删除表达式。以防万一其他人可能需要,下面是我所做的。我从某个地方弄来的课,所以可能很熟悉。我刚刚添加了方法searchAndReplace()

package com.my.docx4j;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;

import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.wml.ContentAccessor;
import org.docx4j.wml.Text;

public class Docx4j {

    public static void main(String[] args) throws Docx4JException, IOException, JAXBException {
        String filePath = "C:\\Users\\markamm\\Documents\\tmp\\";
        String file = "Hello.docx";

        Docx4j docx4j = new Docx4j();
        WordprocessingMLPackage template = docx4j.getTemplate(filePath+file);

//      MainDocumentPart documentPart = template.getMainDocumentPart();

        List<Object> texts = getAllElementFromObject(
                template.getMainDocumentPart(), Text.class);
        searchAndReplace(texts, new HashMap<String, String>(){
            {
                this.put("${abcd_efg.soanother_hello_broken_shit}", "Company Name here...");
                this.put("${I_dont_know}", "Hmmm lemme see");
                this.put("${${damn.right_lol}", "Gotcha!!!");
                this.put("${one_here_and}", "Firstname");
                this.put("${one}", "ChildA");
                this.put("${two}", "ChildB");
                this.put("${three}", "ChildC");
            }
            @Override
            public String get(Object key) {
                // TODO Auto-generated method stub
                return super.get(key);
            }
        });

        docx4j.writeDocxToStream(template, filePath+"Hello2.docx");
    }

    public static void searchAndReplace(List<Object> texts, Map<String, String> values){

        // -- scan all expressions  
        // Will later contain all the expressions used though not used at the moment
        List<String> els = new ArrayList<String>(); 

        StringBuilder sb = new StringBuilder();
        int PASS = 0;
        int PREPARE = 1;
        int READ = 2;
        int mode = PASS;

        // to nullify
        List<int[]> toNullify = new ArrayList<int[]>();
        int[] currentNullifyProps = new int[4];

        // Do scan of els and immediately insert value
        for(int i = 0; i<texts.size(); i++){
            Object text = texts.get(i);
            Text textElement = (Text) text;
            String newVal = "";
            String v = textElement.getValue();
//          System.out.println("text: "+v);
            StringBuilder textSofar = new StringBuilder();
            int extra = 0;
            char[] vchars = v.toCharArray();
            for(int col = 0; col<vchars.length; col++){
                char c = vchars[col];
                textSofar.append(c);
                switch(c){
                case '$': {
                    mode=PREPARE;
                    sb.append(c);
//                  extra = 0;
                } break;
                case '{': {
                    if(mode==PREPARE){
                        sb.append(c);
                        mode=READ;
                        currentNullifyProps[0]=i;
                        currentNullifyProps[1]=col+extra-1;
                        System.out.println("extra-- "+extra);
                    } else {
                        if(mode==READ){
                            // consecutive opening curl found. just read it
                            // but supposedly throw error
                            sb = new StringBuilder();
                            mode=PASS;
                        }
                    }
                } break;
                case '}': {
                    if(mode==READ){
                        mode=PASS;
                        sb.append(c);
                        els.add(sb.toString());
                        newVal +=textSofar.toString()
                                +(null==values.get(sb.toString())?sb.toString():values.get(sb.toString()));
                        textSofar = new StringBuilder();
                        currentNullifyProps[2]=i;
                        currentNullifyProps[3]=col+extra;
                        toNullify.add(currentNullifyProps);
                        currentNullifyProps = new int[4];
                        extra += sb.toString().length();
                        sb = new StringBuilder();
                    } else if(mode==PREPARE){
                        mode = PASS;
                        sb = new StringBuilder();
                    }
                }
                default: {
                    if(mode==READ) sb.append(c);
                    else if(mode==PREPARE){
                        mode=PASS;
                        sb = new StringBuilder();
                    }
                }
                }
            }
            newVal +=textSofar.toString();
            textElement.setValue(newVal);
        }

        // remove original expressions
        if(toNullify.size()>0)
        for(int i = 0; i<texts.size(); i++){
            if(toNullify.size()==0) break;
            currentNullifyProps = toNullify.get(0);
            Object text = texts.get(i);
            Text textElement = (Text) text;
            String v = textElement.getValue();
            StringBuilder nvalSB = new StringBuilder();
            char[] textChars = v.toCharArray();
            for(int j = 0; j<textChars.length; j++){
                char c = textChars[j];
                if(null==currentNullifyProps) {
                    nvalSB.append(c);
                    continue;
                }
                // I know 100000 is too much!!! And so what???
                int floor = currentNullifyProps[0]*100000+currentNullifyProps[1];
                int ceil = currentNullifyProps[2]*100000+currentNullifyProps[3];
                int head = i*100000+j;
                if(!(head>=floor && head<=ceil)){
                    nvalSB.append(c);
                } 

                if(j>currentNullifyProps[3] && i>=currentNullifyProps[2]){
                    toNullify.remove(0);
                    if(toNullify.size()==0) {
                        currentNullifyProps = null;
                        continue;
                    }
                    currentNullifyProps = toNullify.get(0);
                }
            }
            textElement.setValue(nvalSB.toString());
        }
    }

    private WordprocessingMLPackage getTemplate(String name)
            throws Docx4JException, FileNotFoundException {
        WordprocessingMLPackage template = WordprocessingMLPackage
                .load(new FileInputStream(new File(name)));
        return template;
    }

    private static List<Object> getAllElementFromObject(Object obj,
            Class<?> toSearch) {
        List<Object> result = new ArrayList<Object>();
        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;
    }

    private void replacePlaceholder(WordprocessingMLPackage template,
            String name, String placeholder) {
        List<Object> texts = getAllElementFromObject(
                template.getMainDocumentPart(), Text.class);

        for (Object text : texts) {
            Text textElement = (Text) text;
            if (textElement.getValue().equals(placeholder)) {
                textElement.setValue(name);
            }
        }
    }

    private void writeDocxToStream(WordprocessingMLPackage template,
            String target) throws IOException, Docx4JException {
        File f = new File(target);
        template.save(f);
    }
}
 类似资料:
  • 您不需要理解内容,只需查看我的占位符和。有10页与这些占位符,现在我应该取代他们与其他内容。黑色和黄色的盒子是公司的照片,我不会分享。 现在,我开始阅读整个docx4j文档,并在一段时间后生成以下代码: 一些解释: 是上图中文件的路径 是应该替换的值 是应该替换的值 但是当我运行这个方法时,什么也没有发生,我的控制台只是打印一些信息。如果它们很重要,我会编辑帖子,但我不这么认为。 那么我的错在哪里

  • 问题内容: 对于我的项目,我需要将有向图转换为图的张量流实现,就好像它是神经网络一样。在tensorflow版本1中,我可以将所有输入定义为占位符,然后使用广度优先搜索图为输出生成数据流图。然后,我只需使用feed_dict来输入我的输入。但是,在TensorFlow v2.0中,他们决定完全放弃占位符。 如何在不使用占位符的情况下为每个接受可变数量的输入并返回可变数量的输出的图制作tf.func

  • 问题内容: 使用pysqlite我正在制定一个程序来处理一些数据。对多个表和列中的相似字段执行相同类型的操作,因此我认为我可以参数化sql语句,如下所示: 我得到的错误不是很有帮助(),但我明白了:Pysqlite不赞赏以这种方式使用占位符。 谁能指出正在发生的事情以及执行上述操作的正确方法? 问题答案: 您根本不能将占位符用于列或表名。我对此没有权威的引用-我只是从尝试过和失败中“知道”这一点。

  • 我的问题的背景是,我试图本地化一些HTML文件,但我不想为每种语言拥有完整的HTML副本,我只想“以Android的方式”做到这一点,并在我的HTML中使用本地化字符串资源。 假设我在一个字符串中有一些HTML,在将HTML发送到WebView之前,应该用字符串资源替换占位符--我如何做到这一点? 和这些字符串资源: 现在,举一个简单的例子,我可以使用string.replace(),但是如果我想

  • 有没有办法让程序迭代所有出现的“[序列号]”并用字符串替换它们?这些标记中的许多将在一个大表中,那么Apache POI中是否有一些等效的命令来只在word中按Ctrl+F并使用replace All? 如有任何建议,不胜感激,谢谢

  • 有没有办法做到这一点?