From c3f21795e87850c7447bb265513299c940b779c6 Mon Sep 17 00:00:00 2001 From: Joseph Verron Date: Mon, 4 Nov 2024 23:45:25 +0800 Subject: [PATCH] refactor: remove DocumentWalker and integrate docx4j TraversalUtil Use docx4j TraversalUtil and ClassFinder to replace expressions in paragraphs. This change simplifies the codebase by removing redundant classes and leveraging library utilities. --- .../core/BaseDocumentWalker.java | 55 ------ .../officestamper/core/DocumentWalker.java | 159 ------------------ .../ParagraphResolverDocumentWalker.java | 48 ------ .../processors/repeat/RepeatProcessor.java | 20 ++- 4 files changed, 14 insertions(+), 268 deletions(-) delete mode 100644 engine/src/main/java/pro/verron/officestamper/core/BaseDocumentWalker.java delete mode 100644 engine/src/main/java/pro/verron/officestamper/core/DocumentWalker.java delete mode 100644 engine/src/main/java/pro/verron/officestamper/preset/processors/repeat/ParagraphResolverDocumentWalker.java diff --git a/engine/src/main/java/pro/verron/officestamper/core/BaseDocumentWalker.java b/engine/src/main/java/pro/verron/officestamper/core/BaseDocumentWalker.java deleted file mode 100644 index 73457fe1..00000000 --- a/engine/src/main/java/pro/verron/officestamper/core/BaseDocumentWalker.java +++ /dev/null @@ -1,55 +0,0 @@ -package pro.verron.officestamper.core; - -import org.docx4j.wml.CommentRangeEnd; -import org.docx4j.wml.CommentRangeStart; -import org.docx4j.wml.P; -import org.docx4j.wml.R; -import pro.verron.officestamper.api.DocxPart; - -/** - * This class is an abstract implementation of the {@link DocumentWalker} interface. - * It implements all methods of the interface and does nothing in the individual methods. - * This makes it easier to implement a custom {@link DocumentWalker} because the implementor - * only has to implement the methods that are of interest. - * - * @author Joseph Verron - * @author Tom Hombergs - * @version ${version} - * @since 1.0.0 - */ -public abstract class BaseDocumentWalker extends DocumentWalker { - - /** - * Creates a new document walker that walks through the given document. - * - */ - protected BaseDocumentWalker(DocxPart contentAccessor) { - super(contentAccessor); - } - - /** - * {@inheritDoc} - */ - @Override - protected void onParagraph(P paragraph) { - - } - - /** {@inheritDoc} */ - @Override - protected void onCommentRangeStart(CommentRangeStart commentRangeStart) { - - } - - /** {@inheritDoc} */ - @Override - protected void onCommentRangeEnd(CommentRangeEnd commentRangeEnd) { - - } - - /** {@inheritDoc} */ - @Override - protected void onCommentReference(R.CommentReference commentReference) { - - } -} diff --git a/engine/src/main/java/pro/verron/officestamper/core/DocumentWalker.java b/engine/src/main/java/pro/verron/officestamper/core/DocumentWalker.java deleted file mode 100644 index 52a9a38c..00000000 --- a/engine/src/main/java/pro/verron/officestamper/core/DocumentWalker.java +++ /dev/null @@ -1,159 +0,0 @@ -package pro.verron.officestamper.core; - -import org.docx4j.XmlUtils; -import org.docx4j.wml.*; -import org.docx4j.wml.R.CommentReference; -import pro.verron.officestamper.api.DocxPart; - -/** - * This class walks the document and calls abstract methods for each element it encounters. - * The following elements are supported: - * - * The following elements are not supported: - * - * - * @author Joseph Verron - * @author Tom Hombergs - * @version ${version} - * @since 1.0.0 - */ -public abstract class DocumentWalker { - - private final DocxPart source; - - /** - * Creates a new DocumentWalker that will traverse the given document. - * - * @param source the document to traverse. - */ - protected DocumentWalker(DocxPart source) { - this.source = source; - } - - /** - * Starts the traversal of the document. - */ - public void walk() { - for (Object content : source.content()) { - Object ue = XmlUtils.unwrap(content); - if (ue instanceof P o) walkParagraph(o); - else if (ue instanceof R o) walkRun(o); - else if (ue instanceof Tbl o) walkTable(o); - else if (ue instanceof Tr o) walkTableRow(o); - else if (ue instanceof Tc o) walkTableCell(o); - else if (ue instanceof CommentRangeStart o) onCommentRangeStart(o); - else if (ue instanceof CommentRangeEnd o) onCommentRangeEnd(o); - else if (ue instanceof CommentReference o) onCommentReference(o); - } - } - - private void walkTable(Tbl table) { - for (Object contentElement : table.getContent()) { - Object unwrappedObject = XmlUtils.unwrap(contentElement); - if (unwrappedObject instanceof Tr row) { - walkTableRow(row); - } - } - } - - private void walkTableRow(Tr row) { - for (Object rowContentElement : row.getContent()) { - Object unwrappedObject = XmlUtils.unwrap(rowContentElement); - if (unwrappedObject instanceof Tc cell) { - walkTableCell(cell); - } - } - } - - private void walkTableCell(Tc cell) { - for (Object cellContentElement : cell.getContent()) { - Object unwrappedObject = XmlUtils.unwrap(cellContentElement); - if (unwrappedObject instanceof P) { - P p = (P) cellContentElement; - walkParagraph(p); - } - else if (unwrappedObject instanceof R) { - R r = (R) cellContentElement; - walkRun(r); - } - else if (unwrappedObject instanceof Tbl nestedTable) { - walkTable(nestedTable); - } - else if (unwrappedObject instanceof CommentRangeStart commentRangeStart) { - onCommentRangeStart(commentRangeStart); - } - else if (unwrappedObject instanceof CommentRangeEnd commentRangeEnd) { - onCommentRangeEnd(commentRangeEnd); - } - } - } - - private void walkParagraph(P p) { - onParagraph(p); - for (Object element : p.getContent()) { - Object unwrappedObject = XmlUtils.unwrap(element); - if (unwrappedObject instanceof R r) { - walkRun(r); - } - else if (unwrappedObject instanceof CommentRangeStart commentRangeStart) { - onCommentRangeStart(commentRangeStart); - } - else if (unwrappedObject instanceof CommentRangeEnd commentRangeEnd) { - onCommentRangeEnd(commentRangeEnd); - } - } - } - - private void walkRun(R r) { - for (Object element : r.getContent()) { - Object unwrappedObject = XmlUtils.unwrap(element); - if (unwrappedObject instanceof CommentReference commentReference) { - onCommentReference(commentReference); - } - } - } - - /** - * This method is called for every {@link P} element in the document. - * - * @param paragraph the {@link P} element to process. - */ - protected abstract void onParagraph(P paragraph); - - /** - * This method is called for every {@link CommentRangeStart} element in the document. - * - * @param commentRangeStart the {@link CommentRangeStart} element to process. - */ - protected abstract void onCommentRangeStart(CommentRangeStart commentRangeStart); - - /** - * This method is called for every {@link CommentRangeEnd} element in the document. - * - * @param commentRangeEnd the {@link CommentRangeEnd} element to process. - */ - protected abstract void onCommentRangeEnd(CommentRangeEnd commentRangeEnd); - - /** - * This method is called for every {@link CommentReference} element in the document. - * - * @param commentReference the {@link CommentReference} element to process. - */ - protected abstract void onCommentReference(CommentReference commentReference); -} diff --git a/engine/src/main/java/pro/verron/officestamper/preset/processors/repeat/ParagraphResolverDocumentWalker.java b/engine/src/main/java/pro/verron/officestamper/preset/processors/repeat/ParagraphResolverDocumentWalker.java deleted file mode 100644 index 9ff0f22c..00000000 --- a/engine/src/main/java/pro/verron/officestamper/preset/processors/repeat/ParagraphResolverDocumentWalker.java +++ /dev/null @@ -1,48 +0,0 @@ -package pro.verron.officestamper.preset.processors.repeat; - -import org.docx4j.wml.P; -import org.docx4j.wml.Tr; -import pro.verron.officestamper.api.DocxPart; -import pro.verron.officestamper.api.ParagraphPlaceholderReplacer; -import pro.verron.officestamper.core.BaseDocumentWalker; -import pro.verron.officestamper.core.StandardParagraph; - -/** - * Walks through a document and replaces expressions with values from the given - * expression context. - * This walker only replaces expressions in paragraphs, not in tables. - * - * @author Joseph Verron - * @version ${version} - * @since 1.4.7 - */ -class ParagraphResolverDocumentWalker - extends BaseDocumentWalker { - private final Object expressionContext; - private final DocxPart docxPart; - private final ParagraphPlaceholderReplacer placeholderReplacer; - - /** - *

Constructor for ParagraphResolverDocumentWalker.

- * - * @param rowClone The row to start with - * @param expressionContext The context of the expressions to resolve - * @param replacer The placeholderReplacer to use for resolving - */ - public ParagraphResolverDocumentWalker( - DocxPart docxPart, Tr rowClone, Object expressionContext, ParagraphPlaceholderReplacer replacer - ) { - super(docxPart.from(rowClone)); - this.expressionContext = expressionContext; - this.docxPart = docxPart; - this.placeholderReplacer = replacer; - } - - /** - * {@inheritDoc} - */ - @Override protected void onParagraph(P paragraph) { - var standardParagraph = StandardParagraph.from(docxPart, paragraph); - placeholderReplacer.resolveExpressionsForParagraph(docxPart, standardParagraph, expressionContext); - } -} diff --git a/engine/src/main/java/pro/verron/officestamper/preset/processors/repeat/RepeatProcessor.java b/engine/src/main/java/pro/verron/officestamper/preset/processors/repeat/RepeatProcessor.java index 59f03f1c..2aa66b84 100644 --- a/engine/src/main/java/pro/verron/officestamper/preset/processors/repeat/RepeatProcessor.java +++ b/engine/src/main/java/pro/verron/officestamper/preset/processors/repeat/RepeatProcessor.java @@ -1,13 +1,17 @@ package pro.verron.officestamper.preset.processors.repeat; +import org.docx4j.TraversalUtil; import org.docx4j.XmlUtils; +import org.docx4j.finders.ClassFinder; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.wml.Comments; +import org.docx4j.wml.P; import org.docx4j.wml.Tbl; import org.docx4j.wml.Tr; import org.springframework.lang.Nullable; import pro.verron.officestamper.api.*; import pro.verron.officestamper.core.CommentUtil; +import pro.verron.officestamper.core.StandardParagraph; import pro.verron.officestamper.preset.CommentProcessorFactory; import java.math.BigInteger; @@ -82,10 +86,14 @@ private void repeatRows(DocxPart source) { Comments.Comment comment = requireNonNull(commentWrapper.getComment()); BigInteger commentId = comment.getId(); CommentUtil.deleteCommentFromElements(rowClone.getContent(), commentId); - new ParagraphResolverDocumentWalker(source, - rowClone, - expressionContext, - this.placeholderReplacer).walk(); + var classFinder = new ClassFinder(P.class); + TraversalUtil.visit(rowClone, classFinder); + var objects = classFinder.results; + for (Object object : objects) { + P result = (P) object; + StandardParagraph paragraph = StandardParagraph.from(source, result); + placeholderReplacer.resolveExpressionsForParagraph(source, paragraph, expressionContext); + } changes.add(rowClone); } } @@ -102,8 +110,8 @@ private void repeatRows(DocxPart source) { /** {@inheritDoc} */ @Override public void repeatTableRow(@Nullable List objects) { var tr = this.getParagraph() - .parent(Tr.class) - .orElseThrow(OfficeStamperException.throwing("This paragraph is not in a table row.")); + .parent(Tr.class) + .orElseThrow(OfficeStamperException.throwing("This paragraph is not in a table row.")); tableRowsToRepeat.put(tr, objects); tableRowsCommentsToRemove.put(tr, getCurrentCommentWrapper()); }