title: Generating a .docx document from a .dotx template with docx4j (in an XPages application)
body: <p>I'm using docx4j in an XPages application to create Word documents containing content from an XPage. The Word document (in .docx format) is created based on a template (also in docx.format). This all works fine. However, when I change the template from a .docx to a .dotx format, the Word document (.docx) which is generated cannot be opened. On trying to open the document, I get an error saying that the content causes problems.</p>
  
  <p>Can anyone tell me how to convert a .dotx file to a .docx file using docx4j?</p>
  
  <p>The code I am currently using is:</p>
  
  <pre><code>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&lt;String[]&gt; notesFields = itmNotesFields.getValues();
          Vector&lt;String[]&gt; 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 &lt; 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("&lt;w:attachedTemplate xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" r:id=\"" + rel.getId() + "\"/&gt;", Context.jc, CTRel.class)
          );
  
      return template;
  }
  
      private static List&lt;Object&gt; getAllElementFromObject(Object obj, Class&lt;?&gt; toSearch) {
          List&lt;Object&gt; result = new ArrayList&lt;Object&gt;();
          if (obj instanceof JAXBElement) obj = ((JAXBElement&lt;?&gt;) obj).getValue();
  
          if (obj.getClass().equals(toSearch))
              result.add(obj);
          else if (obj instanceof ContentAccessor) {
              List&lt;?&gt; 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&lt;Object&gt; 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&lt;Object&gt; paragraphs = getAllElementFromObject(template.getMainDocumentPart(), P.class);
  
          P toReplace = null;
          for (Object p : paragraphs) {
              List&lt;Object&gt; 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 &lt; 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&lt;?&gt; texts = getAllElementFromObject(copy, Text.class);
              if (texts.size() &gt; 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&lt;String,String&gt; repl1 = new HashMap&lt;String, String&gt;();
          repl1.put("SJ_FUNCTION", "function1");
          repl1.put("SJ_DESC", "desc1");
          repl1.put("SJ_PERIOD", "period1");
  
          Map&lt;String,String&gt; repl2 = new HashMap&lt;String, String&gt;();
          repl2.put("SJ_FUNCTION", "function2");
          repl2.put("SJ_DESC", "desc2");
          repl2.put("SJ_PERIOD", "period2");
  
          Map&lt;String,String&gt; repl3 = new HashMap&lt;String, String&gt;();
          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&lt;Map&lt;String, String&gt;&gt; textToAdd,
              WordprocessingMLPackage template) throws Docx4JException, JAXBException {
          List&lt;Object&gt; tables = getAllElementFromObject(template.getMainDocumentPart(), Tbl.class);
  
          // 1. find the table
          Tbl tempTable = getTemplateTable(tables, placeholders[0]);
          List&lt;Object&gt; 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&lt;String, String&gt; 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&lt;Object&gt; tables, String templateKey) throws Docx4JException, JAXBException {
          for (Iterator&lt;Object&gt; iterator = tables.iterator(); iterator.hasNext();) {
              Object tbl = iterator.next();
              List&lt;?&gt; textElements = getAllElementFromObject(tbl, Text.class);
              for (Object text : textElements) {
                  Text textElement = (Text) text;
                  if (textElement.getValue() != null &amp;&amp; textElement.getValue().equals(templateKey))
                      return (Tbl) tbl;
              }
          }
          return null;
      }
  
      private static void addRowToTable(Tbl reviewtable, Tr templateRow, Map&lt;String, String&gt; replacements) {
          Tr workingRow = (Tr) XmlUtils.deepCopy(templateRow);
          List&lt;?&gt; 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();
              }
          }
  
  }
  </code></pre>