![JAR search and dependency download from the Maven repository](/logo.png)
org.wickedsource.docxstamper.util.CommentUtil Maven / Gradle / Ivy
package org.wickedsource.docxstamper.util;
import org.docx4j.XmlUtils;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.exceptions.InvalidFormatException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.PartName;
import org.docx4j.openpackaging.parts.WordprocessingML.CommentsPart;
import org.docx4j.wml.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wickedsource.docxstamper.replace.ParagraphWrapper;
import org.wickedsource.docxstamper.walk.BaseDocumentWalker;
import org.wickedsource.docxstamper.walk.DocumentWalker;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
public class CommentUtil {
private static Logger logger = LoggerFactory.getLogger(CommentUtil.class);
private CommentUtil() {
}
/**
* Returns the first comment found for the given docx object. Note that an object is only considered commented if
* the comment STARTS within the object. Comments spanning several objects are not supported by this method.
*
* @param object the object whose comment to load.
* @param document the document in which the object is embedded (needed to load the comment from the comments.xml part).
* @return the concatenated string of all paragraphs of text within the comment or null if the specified object is not
* commented.
* @throws Docx4JException in case of a Docx4J processing error.
*/
public static Comments.Comment getCommentFor(ContentAccessor object, WordprocessingMLPackage document) throws Docx4JException {
for (Object contentObject : object.getContent()) {
if (contentObject instanceof CommentRangeStart) {
try {
BigInteger id = ((CommentRangeStart) contentObject).getId();
CommentsPart commentsPart = (CommentsPart) document.getParts().get(new PartName("/word/comments.xml"));
Comments comments = commentsPart.getContents();
for (Comments.Comment comment : comments.getComment()) {
if (comment.getId().equals(id)) {
return comment;
}
}
} catch (InvalidFormatException e) {
logger.warn(String.format("Error while searching comment. Skipping object %s.", object), e);
}
}
}
return null;
}
public static String getCommentStringFor(ContentAccessor object, WordprocessingMLPackage document) throws Docx4JException {
Comments.Comment comment = getCommentFor(object, document);
return getCommentString(comment);
}
/**
* Returns the string value of the specified comment object.
*/
public static String getCommentString(Comments.Comment comment) {
StringBuilder builder = new StringBuilder();
for (Object commentChildObject : comment.getContent()) {
if (commentChildObject instanceof P) {
builder.append(new ParagraphWrapper((P) commentChildObject).getText());
}
}
return builder.toString();
}
public static void deleteComment(CommentWrapper comment) {
if (comment.getCommentRangeEnd() != null) {
ContentAccessor commentRangeEndParent = (ContentAccessor) comment.getCommentRangeEnd().getParent();
commentRangeEndParent.getContent().remove(comment.getCommentRangeEnd());
deleteCommentReference(commentRangeEndParent, comment.getCommentRangeEnd().getId());
}
if (comment.getCommentRangeStart() != null) {
ContentAccessor commentRangeStartParent = (ContentAccessor) comment.getCommentRangeStart().getParent();
commentRangeStartParent.getContent().remove(comment.getCommentRangeStart());
deleteCommentReference(commentRangeStartParent, comment.getCommentRangeStart().getId());
}
// TODO: also delete comment from comments.xml
}
private static void deleteCommentReference(ContentAccessor parent, BigInteger commentId) {
int index = 0;
Integer indexToDelete = null;
for (Object contentObject : parent.getContent()) {
if (contentObject instanceof R) {
for (Object runContentObject : ((R) contentObject).getContent()) {
Object unwrapped = XmlUtils.unwrap(runContentObject);
if (unwrapped instanceof R.CommentReference) {
BigInteger foundCommentId = ((R.CommentReference) unwrapped).getId();
if (foundCommentId.equals(commentId)) {
indexToDelete = index;
break;
}
}
}
}
index++;
}
if (indexToDelete != null) {
parent.getContent().remove(indexToDelete.intValue());
}
}
public static Map getComments(WordprocessingMLPackage document) {
Map comments = new HashMap<>();
collectCommentRanges(comments, document);
collectComments(comments, document);
return comments;
}
private static void collectCommentRanges(final Map comments, WordprocessingMLPackage document) {
DocumentWalker documentWalker = new BaseDocumentWalker(document.getMainDocumentPart()) {
@Override
protected void onCommentRangeStart(CommentRangeStart commentRangeStart) {
CommentWrapper commentWrapper = comments.get(commentRangeStart.getId());
if (commentWrapper == null) {
commentWrapper = new CommentWrapper();
comments.put(commentRangeStart.getId(), commentWrapper);
}
commentWrapper.setCommentRangeStart(commentRangeStart);
}
@Override
protected void onCommentRangeEnd(CommentRangeEnd commentRangeEnd) {
CommentWrapper commentWrapper = comments.get(commentRangeEnd.getId());
if (commentWrapper == null) {
commentWrapper = new CommentWrapper();
comments.put(commentRangeEnd.getId(), commentWrapper);
}
commentWrapper.setCommentRangeEnd(commentRangeEnd);
}
};
documentWalker.walk();
}
private static void collectComments(final Map comments, WordprocessingMLPackage document) {
try {
CommentsPart commentsPart = (CommentsPart) document.getParts().get(new PartName("/word/comments.xml"));
if (commentsPart != null) {
for (Comments.Comment comment : commentsPart.getContents().getComment()) {
CommentWrapper commentWrapper = comments.get(comment.getId());
if (commentWrapper != null) {
commentWrapper.setComment(comment);
}
}
}
} catch (Docx4JException e) {
throw new IllegalStateException(e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy