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

使用docx4j从.dotx模板生成.docx文档(在XPages应用程序中)

辛盛
2023-03-14

有人能告诉我如何使用docx4j将.dotx文件转换为.docx文件吗?

我当前使用的代码是:

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

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

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

import org.slf4j.impl.*;

import java.io.FileInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.docx4j.wml.*;

import org.apache.commons.lang3.StringUtils;

import java.util.Enumeration;
import java.util.Map;
import java.util.Iterator;
import java.util.Vector;

import lotus.domino.Document;
import lotus.domino.*;

import org.docx4j.openpackaging.parts.WordprocessingML.DocumentSettingsPart;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.parts.relationships.RelationshipsPart;
import org.docx4j.openpackaging.parts.relationships.Namespaces;

public class JavaTemplateDocument {


    public void mainCode(Session session, Document currDoc, String empLang, String templateType, String sArt) throws Exception {

        Database dbCurr = session.getCurrentDatabase(); 
        String viewName = "vieTemplateLookup"; 
        View tview = dbCurr.getView(viewName);
        Vector viewKey = new Vector();
        viewKey.addElement(empLang);
        viewKey.addElement(templateType);
        Document templateDoc = tview.getDocumentByKey(viewKey);
        if (tview.getDocumentByKey(viewKey) == null ) System.out.println("templateDoc is NULL");

        Item itmNotesFields = templateDoc.getFirstItem("NotesFieldList");
        Item itmWordFields = templateDoc.getFirstItem("WordFieldList");

        Vector<String[]> notesFields = itmNotesFields.getValues();
        Vector<String[]> wordFields = itmWordFields.getValues();

        int z = notesFields.size();
        int x = wordFields.size();

        Enumeration e1 = notesFields.elements();

        Enumeration e2 = wordFields.elements();

        WordprocessingMLPackage template = getTemplate("C:\\Temp\\AZG Sample Template.dotx","C:\\Temp\\AZG Sample Template.docx");

        for (int y = 0; y < x; y++) { 
        if (currDoc.hasItem(String.valueOf(notesFields.elementAt(y)))) {
        Item itmNotesName = currDoc.getFirstItem(String.valueOf(notesFields.elementAt(y))); 
        replacePlaceholder(template, itmNotesName.getText(), String.valueOf(wordFields.elementAt(y))); } 
        else {
            replacePlaceholder(template, "", String.valueOf(wordFields.elementAt(y)));
        }
        }

        writeDocxToStream(template, "C:\\Temp\\AZG Sample Document.docx");
        createResponseDocument(dbCurr, currDoc, templateDoc, sArt); 
    }

    private void createResponseDocument(Database dbCurr, Document currDoc, Document templateDoc, String sArt) throws NotesException{

        Document respDoc = dbCurr.createDocument(); // create the response document
        String refVal = currDoc.getUniversalID();

        respDoc.appendItemValue("IsDocTemplate", "1"); 
        if (currDoc.hasItem("Name")) {
            respDoc.appendItemValue("Name", currDoc.getItemValue("Name"));}
        else {System.out.println("Name is not available"); }
        if (currDoc.hasItem("Firstname")) {
            respDoc.appendItemValue("Firstname", currDoc.getItemValue("Firstname"));}
        else {System.out.println("Firstname is not available"); }
        if (currDoc.hasItem("ReferenceTypeTexts")) {
            respDoc.appendItemValue("ReferenceTypeTexts", currDoc.getItemValue("ReferenceTypeTexts"));}
        else {System.out.println("ReferenceTypeTexts is not available"); }
        if (currDoc.hasItem("ReferenceType")) {
            respDoc.appendItemValue("ReferenceType", currDoc.getItemValue("ReferenceType"));}
        else {System.out.println("ReferenceType is not available"); }   
        System.out.println("Append Form value");
        respDoc.appendItemValue("Form", "frmRespTempl"); 


        respDoc.makeResponse(currDoc);
        RichTextItem body = respDoc.createRichTextItem("Body");
        body.embedObject(1454, "", "C:\\Temp\\AZG Sample Document.docx", null);
        respDoc.save();
    }


    /*
     * Create a simple word document that we can use as a template. 
     * For this just open Word, create a new document and save it as template.docx. 
     * This is the word template we'll use to add content to. 
     * The first thing we need to do is load this document with docx4j. 
     */

    private WordprocessingMLPackage getTemplate(String source, String target) throws Docx4JException, FileNotFoundException, IOException { 

    String WORDPROCESSINGML_DOCUMENT = "application/vnd.openxmlformats-   officedocument.wordprocessingml.document.main+xml";
    final ContentType contentType = new ContentType(WORDPROCESSINGML_DOCUMENT);

    String templatePath = source;

    File sourceFile = new File(source);
    File targetFile = new File(target);
    copyFileUsingFileChannels(sourceFile, targetFile);

    WordprocessingMLPackage template = WordprocessingMLPackage.load(new FileInputStream(targetFile));

    ContentTypeManager ctm = wordMLPackage.getContentTypeManager();
        ctm.addOverrideContentType(new URI("/word/document.xml"),WORDPROCESSINGML_DOCUMENT);

    DocumentSettingsPart dsp = new DocumentSettingsPart();
        CTSettings settings = Context.getWmlObjectFactory().createCTSettings();
        dsp.setJaxbElement(settings);
        wordMLPackage.getMainDocumentPart().addTargetPart(dsp); 

        // Create external rel
        RelationshipsPart rp = RelationshipsPart.createRelationshipsPartForPart(dsp);
        org.docx4j.relationships.Relationship rel = new org.docx4j.relationships.ObjectFactory().createRelationship();
        rel.setType( Namespaces.ATTACHED_TEMPLATE );
        rel.setTarget(templatePath);
        rel.setTargetMode("External");
        rp.addRelationship(rel); // addRelationship sets the rel's @Id 

        settings.setAttachedTemplate(
        (CTRel)XmlUtils.unmarshalString("<w:attachedTemplate xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" r:id=\"" + rel.getId() + "\"/>", Context.jc, CTRel.class)
        );

    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;
    }

    /*
     * This will look for all the Text elements in the document, and those that match are replaced with the value we specify.
     */

    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);
            }
        }
    }

    /*
     * write the document back to a file
     */

    private void writeDocxToStream(WordprocessingMLPackage template, String target) throws IOException, Docx4JException {
        File f = new File(target);
        template.save(f);
    }

    /*
     * Example code for replaceParagraph
     * 
        String placeholder = "SJ_EX1";
        String toAdd = "jos\ndirksen";

        replaceParagraph(placeholder, toAdd, template, template.getMainDocumentPart());
     */

    private void replaceParagraph(String placeholder, String textToAdd, WordprocessingMLPackage template, ContentAccessor addTo) {
        // 1. get the paragraph
        List<Object> paragraphs = getAllElementFromObject(template.getMainDocumentPart(), P.class);

        P toReplace = null;
        for (Object p : paragraphs) {
            List<Object> texts = getAllElementFromObject(p, Text.class);
            for (Object t : texts) {
                Text content = (Text) t;
                if (content.getValue().equals(placeholder)) {
                    toReplace = (P) p;
                    break;
                }
            }
        }

        // we now have the paragraph that contains our placeholder: toReplace
        // 2. split into seperate lines
        String as[] = StringUtils.splitPreserveAllTokens(textToAdd, '\n');

        for (int i = 0; i < as.length; i++) {
            String ptext = as[i];

            // 3. copy the found paragraph to keep styling correct
            P copy = (P) XmlUtils.deepCopy(toReplace);

            // replace the text elements from the copy
            List<?> texts = getAllElementFromObject(copy, Text.class);
            if (texts.size() > 0) {
                Text textToReplace = (Text) texts.get(0);
                textToReplace.setValue(ptext);
            }

            // add the paragraph to the document
            addTo.getContent().add(copy);
        }

        // 4. remove the original one
        ((ContentAccessor)toReplace.getParent()).getContent().remove(toReplace);

    }

    /*
     * A set of hashmaps that contain the name of the placeholder to replace and the value to replace it with. 
     * 
     *  Map<String,String> repl1 = new HashMap<String, String>();
        repl1.put("SJ_FUNCTION", "function1");
        repl1.put("SJ_DESC", "desc1");
        repl1.put("SJ_PERIOD", "period1");

        Map<String,String> repl2 = new HashMap<String, String>();
        repl2.put("SJ_FUNCTION", "function2");
        repl2.put("SJ_DESC", "desc2");
        repl2.put("SJ_PERIOD", "period2");

        Map<String,String> repl3 = new HashMap<String, String>();
        repl3.put("SJ_FUNCTION", "function3");
        repl3.put("SJ_DESC", "desc3");
        repl3.put("SJ_PERIOD", "period3");

        replaceTable(new String[]{"SJ_FUNCTION","SJ_DESC","SJ_PERIOD"}, Arrays.asList(repl1,repl2,repl3), template);
     */

    private void replaceTable(String[] placeholders, List<Map<String, String>> textToAdd,
            WordprocessingMLPackage template) throws Docx4JException, JAXBException {
        List<Object> tables = getAllElementFromObject(template.getMainDocumentPart(), Tbl.class);

        // 1. find the table
        Tbl tempTable = getTemplateTable(tables, placeholders[0]);
        List<Object> rows = getAllElementFromObject(tempTable, Tr.class);

        // first row is header, second row is content
        if (rows.size() == 2) {
            // this is our template row
            Tr templateRow = (Tr) rows.get(1);

            for (Map<String, String> replacements : textToAdd) {
                // 2 and 3 are done in this method
                addRowToTable(tempTable, templateRow, replacements);
            }

            // 4. remove the template row
            tempTable.getContent().remove(templateRow);
        }
    }

    private Tbl getTemplateTable(List<Object> tables, String templateKey) throws Docx4JException, JAXBException {
        for (Iterator<Object> iterator = tables.iterator(); iterator.hasNext();) {
            Object tbl = iterator.next();
            List<?> textElements = getAllElementFromObject(tbl, Text.class);
            for (Object text : textElements) {
                Text textElement = (Text) text;
                if (textElement.getValue() != null && textElement.getValue().equals(templateKey))
                    return (Tbl) tbl;
            }
        }
        return null;
    }

    private static void addRowToTable(Tbl reviewtable, Tr templateRow, Map<String, String> replacements) {
        Tr workingRow = (Tr) XmlUtils.deepCopy(templateRow);
        List<?> textElements = getAllElementFromObject(workingRow, Text.class);
        for (Object object : textElements) {
            Text text = (Text) object;
            String replacementValue = (String) replacements.get(text.getValue());
            if (replacementValue != null)
                text.setValue(replacementValue);
        }

        reviewtable.getContent().add(workingRow);
    }

private static void copyFileUsingFileChannels(File source, File dest)
                throws IOException {
            FileChannel inputChannel = null;
            FileChannel outputChannel = null;
            try {
                inputChannel = new FileInputStream(source).getChannel();
                outputChannel = new FileOutputStream(dest).getChannel();
                outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
            } finally {
                inputChannel.close();
                outputChannel.close();
            }
        }

}

共有1个答案

汪阳飇
2023-03-14

一般而言,模板(.dotx)和文档(.docx)之间有几个区别。这意味着您需要做一些事情--无论您是将文档保存为模板,还是试图从模板创建文档,这都不是仅仅更改文件扩展名那么简单。

希望本大纲将有助于:

  1. 首先执行您已经执行的操作:您的新文档应该是模板的文件副本
  2. 根据需要更改新的WordProcessingMLPackage的文档类型(请参阅ContentTypes类中的WordProcessingML_Template
  3. 创建附加模板并将其附加到文档:有关此方面的详细信息,请参阅Github上的示例代码(TemplateAttach.java示例)。

 类似资料:
  • 我正在尝试用不同的数据填充docx模板,但我无法取得任何进展。我试过两种方法。第一个使用java代码,第二个使用内容控件绑定。对于第一种方法,我使用本教程http://www.smartjava.org/content/create-complex-word-docx-documents-programatically-docx4j,对于第二种方法,使用本教程https://github.com/

  • 我们最近在一个项目中使用了docx4j,这个项目需要通过变量注入从模板生成docx。为此,我们购买了plutext-enterprise libs,以便能够合并多个文档,并结合变量注入:

  • 我面临的例外情况如下: java.lang.nosuchmethoderror:org.apache.xml.utils.DefaulTerrorHandler.(Z)V在org.docx4j.org.apache.xalan.transformer.transformerIdentityImpl.(TransformerIdentityImpl.transformerIdentityImpl.(

  • 模板使用方式 protoc-gen-doc 插件支持模板,可以通过使用不同的模板来定制输出的内容和格式,命令如下: protoc --doc_out=/usr/local/include/dolphin/api.mustache,index.html:../../../target/contract-doc userService.proto 只是简单的将原来 --doc_out=html,* 中

  • 编辑:我发现如果我向UnmarshallFromTemplate.docx添加一些文本并保存它,它不会替换新的文本行。-标记以某种方式拆分为多个标记: 编辑document.xml中的文本并添加缺少的信息没有多大帮助。 编辑2: 伙计们。我找到了一个非常适合自己的解决办法,不知道为什么花了这么长时间才弄明白。正如我所说的:运行在哪里分裂,原因是在我看来是${}。因此,我只是在占位符之前使用了一个#