如何使用Java编辑MS Word文档?

时间:2014-09-24 11:37:45

标签: java io ms-word

我的Word模板很少,我的要求是使用Java根据用户输入替换文档中的一些单词/占位符。我尝试了很多库,包括2-3个版本的docx4j,但没有什么效果很好,它们都没有做任何事情!

我知道之前已经问过这个问题,但我尝试了所有我知道的选项。那么,使用什么java库我可以“真正”替换/编辑这些模板?我倾向于“易于使用/几行代码”类型库。

我正在使用Java 8,我的MS Word模板在MS Word 2007中。

更新

此代码是使用SO成员Joop Eggen

提供的代码示例编写的
public Main() throws URISyntaxException, IOException, ParserConfigurationException, SAXException
    {
        URI docxUri = new URI("C:/Users/Yohan/Desktop/yohan.docx");
        Map<String, String> zipProperties = new HashMap<>();
        zipProperties.put("encoding", "UTF-8");

         FileSystem zipFS = FileSystems.newFileSystem(docxUri, zipProperties);

           Path documentXmlPath = zipFS.getPath("/word/document.xml");

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

            factory.setNamespaceAware(true);
            DocumentBuilder builder = factory.newDocumentBuilder();

            Document doc = builder.parse(Files.newInputStream(documentXmlPath));

            byte[] content = Files.readAllBytes(documentXmlPath);
            String xml = new String(content, StandardCharsets.UTF_8);
            //xml = xml.replace("#DATE#", "2014-09-24");
            xml = xml.replace("#NAME#", StringEscapeUtils.escapeXml("Sniper"));

            content = xml.getBytes(StandardCharsets.UTF_8);
            Files.write(documentXmlPath, content);
    }

然而,这会返回以下错误

java.nio.file.ProviderNotFoundException: Provider "C" Not found

at: java.nio.file.FileSystems.newFileSystem(FileSystems.java:341) at java.nio.file.FileSystems.newFileSystem(FileSystems.java:341)

at java.nio.fileFileSystems.newFileSystem(FileSystems.java:276)

4 个答案:

答案 0 :(得分:3)

可以使用docx(带有XML和其他文件的zip)java zip文件系统和XML或文本处理。

URI docxUri = ,,, // "jar:file:/C:/... .docx"
Map<String, String> zipProperties = new HashMap<>();
zipProperties.put("encoding", "UTF-8");
try (FileSystem zipFS = FileSystems.newFileSystem(docxUri, zipProperties)) {
    Path documentXmlPath = zipFS.getPath("/word/document.xml");

使用XML时:

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

    factory.setNamespaceAware(true);
    DocumentBuilder builder = factory.newDocumentBuilder();

    Document doc = builder.parse(Files.newInputStream(documentXmlPath));
    //Element root = doc.getDocumentElement();

然后,您可以使用XPath查找位置,并再次写回XML。

甚至可能是您不需要XML但可以取代占位符:

    byte[] content = Files.readAllBytes(documentXmlPath);
    String xml = new String(content, StandardCharsets.UTF_8);
    xml = xml.replace("#DATE#", "2014-09-24");
    xml = xml.replace("#NAME#", StringEscapeUtils.escapeXml("Sniper")));
    ...
    content = xml.getBytes(StandardCharsets.UTF_8);
    Files.delete(documentXmlPath);
    Files.write(documentXmlPath, content);

要进行快速开发,请将.docx的副本重命名为带.zip文件扩展名的名称,然后检查文件。

File.write应该已经应用了StandardOpenOption.TRUNCATE_EXISTING,但我添加了Files.delete,因为发生了一些错误。见评论。

答案 1 :(得分:3)

试试Apache POIPOI可以与docdocx一起使用,但docx更有文档记录,因此可以更好地支持它。

UPD :您可以使用使用POI的XDocReport。另外,我建议将xlsx用于模板,因为它更适合more documented

答案 2 :(得分:2)

我已经花了几天时间讨论这个问题,直到我发现产生差异的是FileSystem实例上的try-with-resources,出现在Joop Eggen的代码片段中,但没有问题片段:
try (FileSystem zipFS = FileSystems.newFileSystem(docxUri, zipProperties))
如果没有此try-with-resources块,则FileSystem资源将不会关闭(如Java tutorial中所述),并且未修改word文档。

答案 3 :(得分:0)

稍微退一步,有大约4种不同的方法来编辑单词/占位符:

  • MERGEFIELD或DOCPROPERTY字段(如果您在docx4j中遇到此问题,那么您可能没有正确设置输入docx)
  • content control databinding
  • 文档表面上的变量替换(在DOM / SAX级别,或使用库)
  • 做XHTML,然后是import that

在选择之前,您应该决定是否还需要能够处理:

  • 重复数据(例如添加表格行)
  • 有条件的内容(例如,将存在或不存在的整个段落)
  • 添加图片

如果您需要这些,那么MERGEFIELD或DOCPROPERTY字段可能已经输出(尽管您也可以使用IF字段,如果您可以找到支持它们的库)。并且添加图像使得DOM / SAX操作在其他一个答案中被提倡,更加容易和容易出错。

要考虑的其他事项是:

  • 你的作者:他们有多技术?这对创作UI意味着什么?
  • 你提到的用于变量替换的“用户输入”是给定的,还是将其解决为你正在解决的问题的一部分?