【问题标题】:how to append data in docx file using docx4j如何使用 docx4j 在 docx 文件中追加数据
【发布时间】:2011-06-16 06:12:25
【问题描述】:

请告诉我如何使用 java 和 docx4j 在 docx 文件中追加数据。

我正在做的是,我使用的是 docx 格式的模板,其中一些字段在运行时被 java 删除,

我的问题是它为每组数据创建一个新文件,我只想将新文件附加到 1 个文件中。这不是使用 java 流完成的

String outputfilepath = "e:\\Practice/DOC/output/generatedLatterOUTPUT.docx";
String outputfilepath1 = "e:\\Practice/DOC/output/generatedLatterOUTPUT1.docx";
WordprocessingMLPackage wordMLPackage;

public void templetsubtitution(String name, String age, String gender, Document document)
        throws Exception {

    // input file name
    String inputfilepath = "e:\\Practice/DOC/profile.docx";
    // out put file name

    // id of Xml file
    String itemId1 = "{A5D3A327-5613-4B97-98A9-FF42A2BA0F74}".toLowerCase();
    String itemId2 = "{A5D3A327-5613-4B97-98A9-FF42A2BA0F74}".toLowerCase();
    String itemId3 = "{A5D3A327-5613-4B97-98A9-FF42A2BA0F74}".toLowerCase();
    // Load the Package

    if (inputfilepath.endsWith(".xml")) {

        JAXBContext jc = Context.jcXmlPackage;
        Unmarshaller u = jc.createUnmarshaller();
        u.setEventHandler(new org.docx4j.jaxb.JaxbValidationEventHandler());

        org.docx4j.xmlPackage.Package wmlPackageEl = (org.docx4j.xmlPackage.Package) ((JAXBElement) u
                .unmarshal(new javax.xml.transform.stream.StreamSource(
                        new FileInputStream(inputfilepath)))).getValue();

        org.docx4j.convert.in.FlatOpcXmlImporter xmlPackage = new org.docx4j.convert.in.FlatOpcXmlImporter(
                wmlPackageEl);

        wordMLPackage = (WordprocessingMLPackage) xmlPackage.get();

    } else {
        wordMLPackage = WordprocessingMLPackage
                .load(new File(inputfilepath));
    }

    CustomXmlDataStoragePart customXmlDataStoragePart = wordMLPackage
            .getCustomXmlDataStorageParts().get(itemId1);
    // Get the contents
    CustomXmlDataStorage customXmlDataStorage = customXmlDataStoragePart
            .getData();
    // Change its contents
    ((CustomXmlDataStorageImpl) customXmlDataStorage).setNodeValueAtXPath(
            "/ns0:orderForm[1]/ns0:record[1]/ns0:name[1]", name,
            "xmlns:ns0='EasyForm'");

    customXmlDataStoragePart = wordMLPackage.getCustomXmlDataStorageParts()
            .get(itemId2);
    // Get the contents
    customXmlDataStorage = customXmlDataStoragePart.getData();
    // Change its contents
    ((CustomXmlDataStorageImpl) customXmlDataStorage).setNodeValueAtXPath(
            "/ns0:orderForm[1]/ns0:record[1]/ns0:age[1]", age,
            "xmlns:ns0='EasyForm'");

    customXmlDataStoragePart = wordMLPackage.getCustomXmlDataStorageParts()
            .get(itemId3);
    // Get the contents
    customXmlDataStorage = customXmlDataStoragePart.getData();
    // Change its contents
    ((CustomXmlDataStorageImpl) customXmlDataStorage).setNodeValueAtXPath(
            "/ns0:orderForm[1]/ns0:record[1]/ns0:gender[1]", gender,
            "xmlns:ns0='EasyForm'");

    // Apply the bindings
    BindingHandler.applyBindings(wordMLPackage.getMainDocumentPart());
    File f = new File(outputfilepath);
    wordMLPackage.save(f);
    FileInputStream fis = new FileInputStream(f);
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    byte[] buf = new byte[1024];
    try {
        for (int readNum; (readNum = fis.read(buf)) != -1;) {
            bos.write(buf, 0, readNum);
        }
        // System.out.println( buf.length);

    } catch (IOException ex) {
    }
    byte[] bytes = bos.toByteArray();
    FileOutputStream file = new FileOutputStream(outputfilepath1, true);
    DataOutputStream out = new DataOutputStream(file);
    out.write(bytes);
    out.flush();
    out.close();

    System.out.println("..done");
}

public static void main(String[] args) {
  utility u = new utility();
  u.templetsubtitution("aditya",24,mohan);
}

提前致谢

【问题讨论】:

  • er 看起来像 Apache POI 而不是 docx4j?
  • 对我来说看起来像 docx4j :-)。您的方法 Templetsubtitution 每次调用时都会发出一个新的 docx。如果您想要所有数据组的单个 docx,则需要重构。
  • @plutext - 你没有看到原帖:)

标签: java docx4j


【解决方案1】:

如果我理解正确,您实际上是在谈论合并文档。您可以使用两种非常简单的方法,它们的有效性实际上取决于数据的结构和后续使用:

  1. PhilippeAuriach 在他的回答中描述了一种方法,它需要 将MaindocumentPart 实例中的所有组件附加到 其他。就最终的 docx 文件而言,这意味着内容 出现在document.xml - 它不会考虑标题 和页脚(例如),但这对你来说可能没问题。

  2. 您可以通过将多个文档插入到单个 docx 文件中 作为 AltChunk 元素(请参阅 docx4j 文档)。这会 将一个 Word 文件中的所有内容放入另一个文件中,包括标题和所有内容。 这样做的缺点是您的最终文件将不是正确的 流动的 Word 文件,直到您打开它并将其保存在 MS Word 本身中 (导入的组件在 docx 中保留为独立文件 捆)。如果您想生成,这将导致您出现问题 “合并”文件,然后对它们做一些事情,比如渲染 PDF—— 合并的内容将被忽略。

更完整(和复杂)的方法是执行“深度合并”。这会更新和维护文档中保存的所有引用。导入的内容成为文档主要“流程”的一部分(即它不作为单独的引用存储),因此最终结果是一个可以呈现为 PDF 或其他格式的正确合并文件。

这样做的缺点是您需要对 docx 结构和 API 有很好的了解,并且您将编写大量代码(我建议您购买 Plutext's MergeDocx 的许可证)。

【讨论】:

  • 我想在这里添加的第二点是考虑到生成文档的文件大小。例如,我有一个以这种方式生成的文件,它有 14.3 MB,在我打开它并用 MS Word 保存后,它会缩小到 608 KB。这个 14.3 MB 的文件有 197 个 AltChunk,页眉和页脚中有照片。
【解决方案2】:

我不得不处理类似的事情,这就是我所做的(可能不是最有效的,但工作):

  • 创建一个 finalDoc 加载模板,然后清空它(这样你就有了这个文档中的样式)
  • 为每个数据行创建一个加载模板的新文档,然后用您的值替换您的字段
  • 使用下面的函数将填充了数据的文档附加到finalDoc中:

    public static void append(WordprocessingMLPackage docDest, WordprocessingMLPackage docSource) {
    List<Object> objects = docSource.getMainDocumentPart().getContent();
        for(Object o : objects){
            docDest.getMainDocumentPart().getContent().add(o);
        }
    }
    

希望这会有所帮助。

【讨论】:

  • 完美!请记住使用 SaveToZipFile 对象保存修改。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-08
  • 2013-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-14
  • 1970-01-01
相关资源
最近更新 更多