java docx文档解析

几个月前,我需要创建一个包含许多表和段落的动态Word文档。 过去,我曾使用POI来实现此目的,但是我发现它很难使用,并且在创建更复杂的文档时对我来说效果不佳。 因此,对于这个项目,经过一番搜索,我决定使用docx4j 。 Docx4j,根据他们的网站是:

“ docx4j是一个Java库,用于创建和处理Microsoft Open XML(Word docx,Powerpoint pptx和Excel xlsx)文件。
它类似于Microsoft的OpenXML SDK,但适用于Java。

在本文中,我将向您展示几个示例,您可以使用这些示例来生成Word文档的内容。 更具体地说,我们将看以下两个示例:

  • 加载模板Word文档以添加内容并另存为新文档
  • 将段落添加到此模板文档
  • 将表添加到此模板文档

这里的一般方法是首先创建一个Word文档,其中包含最终文档的布局和主要样式。 在本文档中,您将需要添加占位符(简单字符串),我们将使用这些占位符来搜索并替换为真实内容。

例如,一个非常基本的模板如下所示:

在本文中,我们将向您展示如何填充此内容,以便获得此信息:

加载模板Word文档以添加内容并另存为新文档

首先是第一件事。 让我们创建一个简单的Word文档,将其用作模板。 为此,只需打开Word,创建一个新文档并将其另存为template.docx。 这是我们用来向其添加内容的单词模板。 我们需要做的第一件事是用docx4j加载该文档。 您可以使用以下一段Java代码:

private WordprocessingMLPackage getTemplate(String name) throws Docx4JException, FileNotFoundException {WordprocessingMLPackage template = WordprocessingMLPackage.load(new FileInputStream(new File(name)));return template;}

这将返回一个Java对象,该对象表示完整的(此时)空文档。 现在,我们可以使用Docx4J API在此Word文档中添加,删除和修改内容。 Docx4J有许多帮助程序类,可用于遍历此文档。 我确实写了一些帮助程序,尽管它们确实使查找特定的占位符并用实际内容替换它们非常容易。 让我们看看其中之一。 此操作是几个JAXB操作的包装,使您可以搜索特定元素及其所有子元素来查找某个类。 例如,您可以使用它来获取文档中的所有表,表中的所有行等等。

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

没什么复杂的,但真的很有帮助。 让我们看看如何使用此操作。 在此示例中,我们仅将简单的文本占位符替换为其他值。 例如,这是您用来动态设置文档标题的内容。 不过,首先,在您创建的Word模板中添加一个自定义占位符。 我将为此使用SJ_EX1。 我们将用我们的名字替换这个值。 docx4j中的基本文本元素由org.docx4j.wml.Text类表示。 要替换此简单的占位符,我们要做的就是调用此方法:

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

这将查找文档中的所有Text元素,并将匹配的元素替换为我们指定的值。 现在,我们要做的就是将文档写回到文件中。

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

如您所见,并不难。

通过此设置,我们还可以将更复杂的内容添加到Word文档中。 确定如何添加特定内容的最简单方法是查看word文档的XML源代码。 这将告诉您需要哪些包装器以及Word如何编组XML。 对于下一个示例,我们将研究如何添加完整的段落。  

将段落添加到此模板文档

您可能想知道为什么我们需要添加段落? 我们已经可以添加文本了,一个段落不只是一大段文本吗? 好吧,是的,不是。 一段确实看起来像是一段很大的文字,但是您需要考虑的是换行符。 如果您像以前一样添加Text元素,并在文本中添加换行符,则它们不会显示。 如果需要换行,则需要创建一个新段落。 幸运的是,使用Docx4j也很容易做到这一点。
我们将通过以下步骤进行操作:

  1. 从模板中找到要替换的段落
  2. 将输入文本分成单独的行
  3. 对于每一行,根据模板中的段落创建一个新段落
  4. 删除原始段落

我们应该已经拥有的辅助方法不应该太难了。

private void replaceParagraph(String placeholder, String textToAdd, WordprocessingMLPackage template, ContentAccessor addTo) {// 1. get the paragraphList<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 linesString 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 correctP copy = (P) XmlUtils.deepCopy(toReplace);// replace the text elements from the copyList texts = getAllElementFromObject(copy, Text.class);if (texts.size() > 0) {Text textToReplace = (Text) texts.get(0);textToReplace.setValue(ptext);}// add the paragraph to the documentaddTo.getContent().add(copy);}// 4. remove the original one((ContentAccessor)toReplace.getParent()).getContent().remove(toReplace);}

在此方法中,我们用提供的文本替换段落的内容,然后将新段落替换为用addTo指定的参数。

String placeholder = "SJ_EX1";String toAdd = "jos\ndirksen";replaceParagraph(placeholder, toAdd, template, template.getMainDocumentPart());

如果您在Word模板中使用更多内容来运行此程序,则会注意到这些段落将出现在文档的底部。 原因是将段落添加回了主文档。 如果您希望将段落添加到文档中的特定位置(通常需要这样做),则可以将其包装在1×1无边界表格中。 该表被视为段落的父级,可以在此处添加新段落。

将表添加到此模板文档

我想展示的最后一个示例是如何向单词模板添加表格。 实际上,更好的描述是如何在Word模板中填充预定义的表格。 就像我们对简单的文本和段落所做的一样,我们将替换占位符。 对于此示例,向您的Word文档中添加一个简单的表格(您可以随意设置样式)。 向此表添加1个哑行,用作内容模板。 在代码中,我们将查找该行,将其复制,并将内容替换为来自Java代码的新行,如下所示:

  1. 查找包含我们的关键字之一的表
  2. 复制用作行模板的行
  3. 对于每行数据,根据行模板向表中添加一行
  4. 删除原始模板行

与我们在段落中显示的方法相同。 首先,让我们看一下如何提供替换数据。 对于此示例,我仅提供了一组哈希图,其中包含要替换的占位符的名称和要替换为其的值。 我还提供了可以在表格行中找到的替换令牌。

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

现在,这个replaceTable方法是什么样的。

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 tableTbl tempTable = getTemplateTable(tables, placeholders[0]);List<Object> rows = getAllElementFromObject(tempTable, Tr.class);// first row is header, second row is contentif (rows.size() == 2) {// this is our template rowTr templateRow = (Tr) rows.get(1);for (Map<String, String> replacements : textToAdd) {// 2 and 3 are done in this methodaddRowToTable(tempTable, templateRow, replacements);}// 4. remove the template rowtempTable.getContent().remove(templateRow);}}

该方法查找表,获取第一行,并为每个提供的映射向表添加新行。 返回之前,它将删除模板行。 此方法使用两个帮助器:addRowToTable和getTemplateTable。 我们首先来看最后一个:

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

此函数只是查看表是否包含我们的占位符之一。 如果是这样,则返回该表。 addRowToTable操作也非常简单。

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

此方法复制我们的模板,并使用提供的值替换此模板行中的占位符。 该副本将添加到表中。 就是这样。 通过这段代码,我们可以在Word文档中填写套利表,同时保留表的布局和样式。

至此为止。 使用段落和表,您可以创建许多不同类型的文档,这与最常生成的文档类型非常匹配。 但是,也可以使用这种相同的方法将其他类型的内容添加到Word文档中。

参考:来自Smart Java博客的JCG合作伙伴 Jos Dirksen 使用docx4j以编程方式创建复杂的Word(.docx)文档 。

翻译自: https://www.javacodegeeks.com/2012/07/java-word-docx-documents-with-docx4j.html

java docx文档解析

java docx文档解析_带有docx4j的Java Word(.docx)文档相关推荐

  1. 在Springboot环境下,使用Docx4J + Freemarker 完成word docx文件生成与Pdf文件转换(附带兼容linux字体问题处理办法)

    在Springboot环境下,使用Docx4J + Freemarker 完成word docx文件生成与Pdf文件转换(附带兼容linux字体问题处理办法) 前言 效果展示 正文 docx文件模板创 ...

  2. python生成word目录_使用Python更新MS Word .docx文档的目录(目录)

    我使用python包" python-docx"来修改MS Word .docx文档的结构和内容.该软件包无法更新TOC(目录)[Python: Create a "Ta ...

  3. python docx 合并文档 图片_使用python抓取大量简历文档内数据(word:docx;pdf;图片等)输出表格文件...

    1. 文章背景描述: 近期公司有员工离职了,技术岗位的. 让HR招人,招聘进度也太慢了,实在等不及,就撸起袖子自己上.(之前从来没招聘过) 自己在某招聘网站注册后,花了若干人民币,短时间收到大量求职者 ...

  4. java课后习题七解析_《Java基础入门》_课后习题解析.doc

    <Java基础入门>_课后习题解析 <Java基础入门>课后习题 Java开发入门 一.填空题 1.Java的三大体系分别是_JavaSE_____._JavaEE_____. ...

  5. java中注解的解析_全面解析Java中的注解与注释

    注解一.什么是 Annotation? (注解 or 注释)Annotation, 准确的翻译应该是 -- 注解. 和注释的作用完全不一样. Annotation 是JDK5.0及以后版本引入的一个特 ...

  6. java教程解析_【B0666】[java视频教程]全方位深入解析最新版SpringBoot源码新手都能学懂视频教程...

    Java视频教程名称:全方位深入解析最新版SpringBoot源码新手都能学懂视频教程    java自学网[javazx.com]  SpringBoot视频教程   it教程 Java自学网收集整 ...

  7. python导入文档文件_使用python-docx 如何向word中插入文件对象!python有关word的教程...

    实现python文本写入word 准备 我测试使用的Python版本2.7.10,你的版本是Python3.5的话,这里就适合了. 使用Speech API 原理 我们的想法是借软的语音接口,所以我们 ...

  8. java编写代码用什么_如何学习用Java编写代码:为什么要学习以及从哪里开始

    java编写代码用什么 by John Selawsky 约翰·塞劳斯基(John Selawsky) 如何学习用Java编写代码:为什么要学习以及从哪里开始 (How to learn to cod ...

  9. java 著名的应用程序_即刻就业:java的应用程序有哪些

    通常我们一般使用java语言制作web开发,目前市场流行的电商网站等基本都是由java编写后台,著名JavaIDE也是Java写的,比如NetBeans,Eclipse,IDEA,JBuidler等. ...

最新文章

  1. nmap 命令行执行错误_Unimap:一款基于Nmap实现的扫描速度提升工具
  2. AWS无服务开发Lambda系列之本地上传包至Lambda
  3. python的dict实现
  4. Ubuntu 18.04 更改静态IP
  5. Spring:源码解读Spring IOC原理
  6. pku 1185 炮兵阵地
  7. dedecms批量删除文档关键词可以吗
  8. CentOS Linux 7绑定静态IP方法
  9. android support v4 viewstub,Android 控件ViewStub
  10. 文件服务器php源码,php 在服务器上载文件
  11. java优化 pdf_Java性能优化权威指南 PDF扫描[132MB]
  12. 直击固定资产管理痛点,让企业轻松管理海量固定资产
  13. html网页简单实现图片轮播效果,html+css+js简单实现图片轮播效果
  14. Playwright-python 教程
  15. 【运动学】基于matlab EKF姿态估计【含Matlab源码 1638期】
  16. TO B的百度云新品问世/价格腰斩 智能化DNA能撑起百度野心?
  17. 饥荒专用服务器全图显示代码,饥荒联机地图全开代码
  18. 如何用java来打印半圆_如何画半圆 - java
  19. 女朋友让我深夜十二点催她睡觉,我用Python轻松搞定
  20. 计算机网络第七版(谢希仁)第三章——数据链路层课后习题答案

热门文章

  1. Java程序员最常犯的 10 个错误
  2. [初级]Java命令学习系列(六)——jinfo
  3. 关于Java你不知道的10件事
  4. Shell入门(一)之简介
  5. 对ASCALL码的理解
  6. win10操作技巧介绍,很实用!
  7. ssm使用全注解实现增删改查案例——DeptServiceImpl
  8. 高效的SQLSERVER分页查询
  9. SparkSQL性能优化
  10. JAVA实现一个图片上传预览功能