杰瑞科技汇

Java如何用XML生成Word文档?

Word 的 XML 格式

现代的 .docx 文件本质上是一个 ZIP 压缩包,解压后,你会发现它包含多个 XML 文件,其中最重要的是:

Java如何用XML生成Word文档?-图1
(图片来源网络,侵删)
  • document.xml: 文档的主要内容,包括段落、表格、图片等。
  • styles.xml: 定义文档中的样式(如标题、正文、加粗等)。
  • header1.xml, footer1.xml: 页眉和页脚。
  • [Content_Types].xml: 描述包内所有文件的类型。

"生成 Word XML" 可以理解为以下几种操作:

  1. 直接操作 XML 字符串:手动构建符合 document.xml 格式的字符串,然后打包成 .docx
  2. 使用库操作 XML 对象:使用 XML 解析/生成库(如 dom4j)来构建 XML 对象,再转换为字符串并打包。
  3. 使用高级 Word 库:使用专门处理 .docx 的库(如 Apache POI),它们在底层也操作 XML,但为你提供了更高层次的、面向对象的 API,让你无需关心复杂的 XML 结构。

直接拼接 XML 字符串 (不推荐,但原理重要)

这种方法让你完全控制 XML 的每一个字符,但非常繁琐且容易出错,它适合于生成结构极其简单的、固定格式的文档。

原理

  1. 创建一个符合 document.xml 结构的字符串。
  2. 将此字符串和其他必需的 XML 文件(如 styles.xml)一起打包成一个 ZIP 文件。
  3. 将 ZIP 文件的后缀名改为 .docx

缺点

Java如何用XML生成Word文档?-图2
(图片来源网络,侵删)
  • 极易出错:XML 标签必须严格匹配,命名空间不能错。
  • 维护困难:如果需求变化(比如改个样式),需要手动修改一大串字符串。
  • 功能有限:很难处理复杂元素,如图片、复杂表格、页眉页脚等。

示例代码

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class SimpleWordXmlGenerator {
    public static void main(String[] args) {
        // 1. 构建 document.xml 的内容
        String documentXmlContent = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
                "<w:document xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">" +
                "  <w:body>" +
                "    <w:p>" + // 开始一个段落
                "      <w:r>" + // 开始一个文本运行
                "        <w:t>这是一个通过直接拼接 XML 生成的 Word 文档。</w:t>" + // 文本内容
                "      </w:r>" +
                "      <w:r>" +
                "        <w:rPr><w:b/></w:rPr>" + // 文本属性:加粗
                "        <w:t>这段文字是粗体的。</w:t>" +
                "      </w:r>" +
                "    </w:p>" +
                "    <w:p>" +
                "      <w:r>" +
                "        <w:t>当前时间: </w:t>" +
                "      </w:r>" +
                "      <w:r>" +
                "        <w:t>" + new java.util.Date() + "</w:t>" + // 插入动态内容
                "      </w:r>" +
                "    </w:p>" +
                "  </w:body>" +
                "</w:document>";
        // 2. 定义要打包进 .docx 的文件
        // 一个最简 .docx 至少需要 [Content_Types].xml 和 word/_rels/document.xml.rels
        // 以及 word/document.xml 和 word/styles.xml
        // 为了简化,我们只生成核心文件,其他文件可以使用一个“空模板”来获取。
        // 3. 将文件打包成 .docx
        String outputFileName = "SimpleGeneratedDocument.docx";
        try (FileOutputStream fos = new FileOutputStream(outputFileName);
             ZipOutputStream zos = new ZipOutputStream(fos, StandardCharsets.UTF_8)) {
            // 添加 document.xml
            zos.putNextEntry(new ZipEntry("word/document.xml"));
            zos.write(documentXmlContent.getBytes(StandardCharsets.UTF_8));
            zos.closeEntry();
            // 添加 [Content_Types].xml (可以从一个模板中复制)
            String contentTypes = "[Content_Types].xml 内容..."; // 这里应该是一个完整的 [Content_Types].xml 文件内容
            zos.putNextEntry(new ZipEntry("[Content_Types].xml"));
            zos.write(contentTypes.getBytes(StandardCharsets.UTF_8));
            zos.closeEntry();
            // ... 还需要添加 styles.xml, fontTable.xml 等,否则文件会损坏。
            // 这非常复杂,因此强烈建议使用库。
            System.out.println("Word 文档 " + outputFileName + " 生成成功!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意:这个例子为了简化,省略了其他必需的 XML 文件,直接运行这个代码生成的文件可能无法正常打开,这充分说明了直接操作 XML 的复杂性。


使用 XML 库 (如 dom4j) (推荐用于复杂定制)

这种方法比直接拼接字符串更健壮、更易于维护,你使用 dom4j 这样的库来构建 XML DOM 树,然后将其序列化为字符串,再打包成 .docx

优点

Java如何用XML生成Word文档?-图3
(图片来源网络,侵删)
  • 结构清晰:代码与 XML 结构一一对应,易于阅读和维护。
  • 不易出错:库会处理 XML 转义、命名空间等问题。
  • 功能强大:可以方便地构建复杂的 XML 结构。

缺点

  • 你仍然需要了解 Word 的 XML 结构(document.xml 等)。
  • 仍然需要手动处理 .docx 的打包过程(添加其他必需文件)。

示例代码

添加 dom4j 依赖:

<!-- pom.xml -->
<dependency>
    <groupId>org.dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>2.1.4</version>
</dependency>
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class Dom4jWordGenerator {
    public static void main(String[] args) {
        // 1. 使用 dom4j 创建 document.xml
        Document document = DocumentHelper.createDocument();
        Element rootElement = document.addElement("document", "http://schemas.openxmlformats.org/wordprocessingml/2006/main");
        Element body = rootElement.addElement("body");
        // 创建第一个段落
        Element p1 = body.addElement("p");
        Element r1 = p1.addElement("r");
        Element t1 = r1.addElement("t");
        t1.setText("这是使用 dom4j 生成的 Word 文档。");
        // 创建第二个段落,带加粗样式
        Element p2 = body.addElement("p");
        Element r2 = p2.addElement("r");
        // 添加文本属性(加粗)
        Element rPr = r2.addElement("rPr");
        rPr.addElement("b"); // <w:b/>
        Element t2 = r2.addElement("t");
        t2.setText("这个段落是粗体的。");
        // 2. 将 DOM 对象转换为格式化的 XML 字符串
        StringWriter stringWriter = new StringWriter();
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");
        XMLWriter xmlWriter = new XMLWriter(stringWriter, format);
        try {
            xmlWriter.write(document);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String documentXmlContent = stringWriter.toString();
        // 3. 打包成 .docx (同方法一,需要其他文件)
        String outputFileName = "Dom4jGeneratedDocument.docx";
        try (FileOutputStream fos = new FileOutputStream(outputFileName);
             ZipOutputStream zos = new ZipOutputStream(fos, StandardCharsets.UTF_8)) {
            zos.putNextEntry(new ZipEntry("word/document.xml"));
            zos.write(documentXmlContent.getBytes(StandardCharsets.UTF_8));
            zos.closeEntry();
            System.out.println("Word 文档 " + outputFileName + " 生成成功!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意:这个例子同样简化了打包过程,在实际项目中,你可能需要一个完整的 .docx 模板,从中提取出 styles.xml, [Content_Types].xml 等文件,然后替换掉 document.xml


使用 Apache POI (强烈推荐)

这是目前 Java 生态中最流行、功能最强大的 Word 文档操作库,它封装了所有底层的 XML 细节,提供了一套简单易用的 Java API。

优点

  • API 简单直观:你操作的是 XWPFDocument, XWPFParagraph, XWPFRun 等对象,而不是 XML 标签。
  • 功能全面:支持段落、表格、列表、图片、页眉页脚、页码、样式等几乎所有 Word 功能。
  • 社区活跃:文档丰富,遇到问题容易找到解决方案。
  • 无需关心 XML:你只需要关心 Word 文档的逻辑结构,库会帮你处理好所有底层的 XML 和 ZIP 打包。

缺点

  • 对于超大型文档,可能会有性能问题。
  • 需要引入额外的依赖。

示例代码

添加 Apache POI 依赖:

<!-- pom.xml -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.2.5</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.5</version>
</dependency>
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.util.Units;
import java.io.FileOutputStream;
import java.io.IOException;
public class ApachePoiWordGenerator {
    public static void main(String[] args) {
        // 1. 创建一个空的 Word 文档对象
        try (XWPFDocument document = new XWPFDocument()) {
            // 2. 创建一个段落
            XWPFParagraph paragraph = document.createParagraph();
            XWPFRun run = paragraph.createRun();
            // 3. 向段落中添加文本和格式
            run.setText("这是使用 Apache POI 生成的 Word 文档。");
            run.setBold(true); // 设置为粗体
            run.setFontSize(14); // 设置字体大小
            run.setColor("FF0000"); // 设置字体颜色 (红色)
            // 4. 创建第二个段落
            XWPFParagraph paragraph2 = document.createParagraph();
            XWPFRun run2 = paragraph2.createRun();
            run2.setText("POI 非常强大,可以轻松处理复杂的文档结构。");
            run2.addBreak(); // 换行
            run2.setText("比如添加一个列表:");
            // 5. 创建一个列表
            XWPFParagraph listParagraph = document.createParagraph();
            listParagraph.setNumID(listParagraph.getCTP().addNewPPr().addNewNumPr().addNewNumId());
            listParagraph.getCTP().getPPr().getNumPr().getNumId().setVal(1L); // 假设列表ID为1
            XWPFRun listRun = listParagraph.createRun();
            listRun.setText("列表项 1");
            XWPFParagraph listParagraph2 = document.createParagraph();
            listParagraph2.setNumID(listParagraph2.getCTP().addNewPPr().addNewNumPr().addNewNumId());
            listParagraph2.getCTP().getPPr().getNumPr().getNumId().setVal(1L);
            XWPFRun listRun2 = listParagraph2.createRun();
            listRun2.setText("列表项 2");
            // 6. 创建一个表格
            XWPFTable table = document.createTable();
            XWPFTableRow tableRowOne = table.getRow(0);
            tableRowOne.getCell(0).setText("姓名");
            tableRowOne.addNewTableCell().setText("年龄");
            tableRowOne.addNewTableCell().setText("城市");
            XWPFTableRow tableRowTwo = table.createRow();
            tableRowTwo.getCell(0).setText("张三");
            tableRowTwo.getCell(1).setText("30");
            tableRowTwo.getCell(2).setText("北京");
            // 7. 将文档写入 .docx 文件
            try (FileOutputStream out = new FileOutputStream("ApachePoiGeneratedDocument.docx")) {
                document.write(out);
                System.out.println("Word 文档 ApachePoiGeneratedDocument.docx 生成成功!");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

这个例子展示了 POI 的强大之处,几行代码就完成了包含格式文本、列表和表格的复杂文档生成,代码可读性极高。


总结与对比

特性 直接拼接 XML 使用 dom4j 使用 Apache POI
易用性 极差 中等 极佳
可维护性 极差 良好 优秀
功能丰富度 极差 中等 非常全面
性能 取决于字符串拼接 取决于 XML 库 良好,适合大多数场景
学习曲线 需要深入了解 Word XML 结构 需要了解 Word XML 和 XML 库 API 简单,容易上手
推荐场景 几乎不推荐,仅用于学习 XML 结构 需要高度定制化 XML 且 POI 无法满足的极端情况 绝大多数 Java 生成 Word 文档的首选方案

最终建议

对于 99% 的应用场景,强烈推荐使用 Apache POI,它能让你从复杂的底层 XML 细节中解放出来,专注于业务逻辑,极大地提高开发效率和代码质量。

只有在有极其特殊的需求,例如需要生成一个 POI 当前版本不支持或支持得不好的特定 Word 功能,并且你愿意深入研究 Word 的底层 XML 结构时,才考虑使用方法二(dom4j),而方法一(直接拼接字符串)仅作为理解 Word 文件格式的入门示例,不应在生产项目中使用。

分享:
扫描分享到社交APP
上一篇
下一篇