How can I remove all comments from a docx file using docx4j?

I want to remove all comments from docx file using docx4j.

I can remove the actual comments with a code snippet as shown below, but I also have to remove links to comments from the main body of the document (otherwise the document is corrupted), but I cannot figure out how.

CommentsPart cmtsPart = wordMLPackage.getMainDocumentPart().getCommentsPart();
org.docx4j.wml.Comments cmts = cpart.getJaxbElement();
List<Comments.Comment> coms = cmts.getComment();
coms.clear();

      

Any recommendations are appreciated!

I also posted this question on the docx4j forum: http://www.docx4java.org/forums/docx-java-f6/how-to-remove-all-comments-from-docx-file-t1329.html .

Thank.

+3


source to share


2 answers


You can use TraversalUtil to find matching objects (CommentRangeStart, CommentRangeEnd, R.CommentReference) and then remove them.

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBElement;

import org.docx4j.TraversalUtil;
import org.docx4j.TraversalUtil.CallbackImpl;
import org.docx4j.XmlUtils;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.Body;
import org.docx4j.wml.CommentRangeEnd;
import org.docx4j.wml.CommentRangeStart;
import org.docx4j.wml.ContentAccessor;
import org.docx4j.wml.R.CommentReference;
import org.jvnet.jaxb2_commons.ppp.Child;


public class Foo {
public static void main(String[] args) throws Exception {

    WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage
            .load(new java.io.File(System.getProperty("user.dir") + "/Foo.docx"));
    MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();

    org.docx4j.wml.Document wmlDocumentEl = (org.docx4j.wml.Document) documentPart
            .getJaxbElement();
    Body body = wmlDocumentEl.getBody();

    CommentFinder cf = new CommentFinder();
    new TraversalUtil(body, cf);

    for (Child commentElement : cf.commentElements) {
        System.out.println(commentElement.getClass().getName());
        Object parent = commentElement.getParent();
        List<Object> theList = ((ContentAccessor)parent).getContent();
        boolean removeResult = remove(theList, commentElement );
        System.out.println(removeResult);
    }   
}

private static boolean remove(List<Object> theList, Object bm)  {
    // Can't just remove the object from the parent,
    // since in the parent, it may be wrapped in a JAXBElement
    for (Object ox : theList) {
        if (XmlUtils.unwrap(ox).equals(bm)) {
            return theList.remove(ox);
        }
    }
    return false;
}

static class CommentFinder extends CallbackImpl {

    List<Child> commentElements = new ArrayList<Child>();

    @Override
    public List<Object> apply(Object o) {

        if (o instanceof javax.xml.bind.JAXBElement
                && (((JAXBElement)o).getName().getLocalPart().equals("commentReference")
                        || ((JAXBElement)o).getName().getLocalPart().equals("commentRangeStart")
                        || ((JAXBElement)o).getName().getLocalPart().equals("commentRangeEnd")                                      
                        )) {
                System.out.println(((JAXBElement)o).getName().getLocalPart());
                commentElements.add( (Child)XmlUtils.unwrap(o) );
            } else 
        if (o instanceof CommentReference || 
            o instanceof CommentRangeStart || 
            o instanceof CommentRangeEnd) {
            System.out.println(o.getClass().getName());
            commentElements.add((Child)o);
        }
        return null;
    }

        @Override // to setParent
        public void walkJAXBElements(Object parent) {

            List children = getChildren(parent);
            if (children != null) {

                for (Object o : children) {

                    if (o instanceof javax.xml.bind.JAXBElement
                            && (((JAXBElement)o).getName().getLocalPart().equals("commentReference")
                                    || ((JAXBElement)o).getName().getLocalPart().equals("commentRangeStart")
                                    || ((JAXBElement)o).getName().getLocalPart().equals("commentRangeEnd")                                      
                                    )) {

                        ((Child)((JAXBElement)o).getValue()).setParent(XmlUtils.unwrap(parent));
                    } else {                        
                        o = XmlUtils.unwrap(o);
                        if (o instanceof Child) {
                            ((Child)o).setParent(XmlUtils.unwrap(parent));
                        }
                    }


                    this.apply(o);

                    if (this.shouldTraverse(o)) {
                        walkJAXBElements(o);
                    }

                }
            }
        }           
    }   

      



}

+3


source


Jason,

Thanks for the offer; I have implemented the solution (posted below) using TraversalUtil, with a CommentFinder class that finds comments, RangeStarts and CommentRangeEnds and adds them to the list. Then I loop through the list and remove each item using parent.getContent (). Remove (obj).

RangeStart / RangeEnd elements are removed from their parent P nodes as expected, but the CommentReference is not removed from the parent R - if I check for the removeResult value, it is false when the CommentReference is removed. Any idea why this would be the case?

Thanks again.



static class CommentFinder extends CallbackImpl {

    List<Child> commentElements = new ArrayList<Child>();

    @Override
    public List<Object> apply(Object o) {
        if (o instanceof CommentReference || 
            o instanceof CommentRangeStart || 
            o instanceof CommentRangeEnd) {
            commentElements.add((Child) o);
        }
        return null;
    }

    @Override
    public void walkJAXBElements(Object parent) {

        List<Object> children = getChildren(parent);
        if (children != null) {

            for (Object o : children) {
                o = XmlUtils.unwrap(o);
                this.apply(o);
                if (this.shouldTraverse(o)) {
                    walkJAXBElements(o);
                }

            }
        }
    }
}

      

// how it is used

CommentFinder cf = new CommentFinder();
    new TraversalUtil(body, cf);

    for (Child commentElement : cf.commentElements) {
        Object parent = commentElement.getParent();
        if (parent instanceof P) {
            boolean removeResult =  ((P)parent).getContent().remove(commentElement);

        } else if (parent instanceof R) {
            boolean removeResult = ((R)parent).getContent().remove(commentElement);             
        }
    }

      

+1


source







All Articles