Paragraph remove does not move on to the next mergefield

Hi,

I have a template with some start and end mergefields. I have to remove the text in between these and add the text entered by the user in the client. I have attached the template for your reference. I am using paragraph.remove() method when I come across a paragraph between the mergefields that needs to be removed. But somehow after I do this, the aspose processing never goes to the next mergefield and stops processing. Currently, I am using paragraph.removeAllChildren() to remove content(runs) within the start and end mergefields. But this leaves a blank line as it does not remove the paragraph completely.
I think the issue has to do with Paragraph break character. Whenever the paragraph ends with a ControlChar.CR, and I use paragraph.remove(), it does not process the document further.
I have attached the ideal resulting and actual resulting document. Please notice the extra blank lines in the actual resulting document.

I have the following code:

public int visitFieldStart(FieldStart fieldStart) throws Exception {
    String fieldCode = getFieldCode(fieldStart.getField());
    if (fieldCode.equals("NoteStart")) {

        // just move to end mergefield
        documentBuilder.moveToMergeField("NoteEnd",false,false);
        // get current node
        Node end = documentBuilder.getCurrentNode();

        removeSequence(fieldStart, end);

        // insert the user note
        documentBuilder.insertHtml(notesList.get(currentIndex));
        currentIndex++;

        // move to mergefield and remove it
        documentBuilder.moveToMergeField("NoteEnd");

    }
    return VisitorAction.CONTINUE;
}

public void removeSequence(Node start, Node end) throws Exception {

    Node curNode = start;

    boolean isFieldEnd = true;

    // Traverse through all the nodes from FieldStart till FieldEnd
    // of User note start tag to reach the node after the field end
    while (curNode != null && isFieldEnd) {
        Node nextNode = curNode.nextPreOrder(curNode.getDocument());
        if (nextNode.getNodeType() == NodeType.FIELD_END) {
            isFieldEnd = false;
        }
        curNode = nextNode;
    }

    // Get the next node after the FieldEnd
    if (curNode != null) {
        curNode = curNode.nextPreOrder(start.getDocument());
    }

    // Remove nodes till the end node is reached
    while (curNode != null && !curNode.equals(end)) {
        // Move to next node
        Node nextNode = curNode.nextPreOrder(start.getDocument());
        // Check whether current contains end node
        if (curNode.isComposite()) {
            CompositeNode curComposite = (CompositeNode) curNode;
            if (!curComposite.getChildNodes().contains(end) &&
                    !curComposite.getChildNodes().contains(start)) {
                nextNode = curNode.getNextSibling();

                if (!curNode.getText().equals(ControlChar.CR)) {
                    // ideally cureNode.remove should work here, but it
                    // does not go to the next visitFieldStart for the next mergefield
                    ((CompositeNode) curNode).removeAllChildren();
                }
            }
        } else {
            curNode.remove();
        }
        curNode = nextNode;
    }
}

/**
    * Called by Aspose when it encounters a Field end
    *
    * @param fieldEnd FieldEnd for a field
    * @return VisitorAction.CONTINUE
    * @throws Exception
    */
public int visitFieldEnd(FieldEnd fieldEnd) throws Exception
{
    String fieldCode = getFieldCode(fieldEnd.getField());
    if (fieldCode.equals("NoteStart")) {
        // remove the merge field for start tag
        documentBuilder.moveToMergeField("NoteStart");
    }

    return VisitorAction.CONTINUE;
}

please let me know if there is a solution around this issue.

Thanks!!

Hi there,

Thanks for your inquiry. In your case, I suggest you please use the DocumentBuilder.insertHtml in visitFieldEnd method. I have modified your code. Please try the following modified code at your end. Hope this helps you. I have attached the output document with this post for your kind reference.

Document document=new Document(MyDir + "Sample+paragraph+aspose.docx");
TestVisitor visitor = new TestVisitor(document);
document.accept(visitor);
for(Node node : (Iterable<Node>)visitor.compositenodes)
{ 
    node.remove();
}
document.getMailMerge().deleteFields();
document.save(MyDir + "Out.docx");
public int visitFieldEnd(com.aspose.words.FieldEnd fieldEnd) throws Exception
{
    String fieldCode = fieldEnd.getField().getFieldCode();
    if (fieldCode.contains("NoteEnd")) {
        // remove the merge field for start tag
        documentBuilder.moveToMergeField("NoteStart",false,false);
        documentBuilder.insertHtml("**Text by user**");
    }
    return VisitorAction.CONTINUE;
}
public int visitFieldStart(FieldStart fieldStart) throws Exception {
    String fieldCode = fieldStart.getField().getFieldCode();
    if (fieldCode.contains("NoteStart")) {
        // just move to end mergefield
        documentBuilder.moveToMergeField("NoteEnd",false,false);
        // get current node
        Node end = documentBuilder.getCurrentNode();
        removeSequence(fieldStart, end);
    }
    return VisitorAction.CONTINUE;
}
ArrayList compositenodes = new ArrayList();
public void removeSequence(Node start, Node end) throws Exception {
    Node curNode = start;
    boolean isFieldEnd = true;
    // Traverse through all the nodes from FieldStart till FieldEnd
    // of User note start tag to reach the node after the field end
    while (curNode != null && isFieldEnd) {
        Node nextNode = curNode.nextPreOrder(curNode.getDocument());
        if (nextNode.getNodeType() == NodeType.FIELD_END) {
            isFieldEnd = false;
        }
        curNode = nextNode;
    }
    // Get the next node after the FieldEnd
    if (curNode != null) {
        curNode = curNode.nextPreOrder(start.getDocument());
    }
    // Remove nodes till the end node is reached
    while (curNode != null && !curNode.equals(end)) {
        // Move to next node
        Node nextNode = curNode.nextPreOrder(start.getDocument());
        // Check whether current contains end node
        if (curNode.isComposite()) {
            CompositeNode curComposite = (CompositeNode) curNode;
            if (!curComposite.getChildNodes().contains(end) &&
                    !curComposite.getChildNodes().contains(start)) {
                nextNode = curNode.getNextSibling();
                if (!curNode.getText().equals(ControlChar.CR)) {
                    // ideally cureNode.remove should work here, but it
                    // does not go to the next visitFieldStart for the next mergefield
                    ((CompositeNode) curNode).removeAllChildren();
                    compositenodes.add(curNode);
                }
            }
        } else {
            curNode.remove();
        }
        curNode = nextNode;
    }
}

Hi Tahir,
Thanks a lot for your response. Unfortunately, some part of the code does not work for me.
I have questions regarding your reply:

  1. Does removeSequence in your code remove nodes between the start and end nodes? does it remove the start and end as well?
  2. When I use your code, after going through removeSequence for the first time, the documentBuilder does not move on to the next NoteStart mergefield or even the visitFieldEnd for the NoteEnd mergefield. It is always stuck on the first occurrence of the NoteStart mergefield within the document. Hence it does not function correctly. That is why in my previous code, I had to use moveToMergeField to delete the field entirely so that it does not occur again in visitFieldStart.
  3. The visitFieldEnd is not hit immediately after visitFieldStart. It went into vistFieldStart twice and never hit visitFieldEnd.
  4. Which version of Aspose are you using? Should this matter? I am using 13.2.0.0 Aspose Words, Java.

I used the part where you collect nodes in the list compositeNodes and remove it later, that helps to remove any empty paragraphs. thanks for that.
Thanks a lot!

Hi there,

Thanks for your inquiry. I have not found the shared issues while using latest version of Aspose.Words. Please use the latest version of Aspose.Words for Java 14.3.0. I have shared the complete code example in this post. Please execute the following code example at your side using latest version of Aspose.Words and let us know how it goes on your side.

Document document = new Document(MyDir + "Sample+paragraph+aspose.docx");
TestVisitor visitor = new TestVisitor(document);
document.accept(visitor);
for (Node node : (Iterable<Node>)visitor.compositenodes)
{
    node.remove();
}
document.getMailMerge().deleteFields();
document.save(MyDir + "Out.docx");
public class TestVisitor extends DocumentVisitor {
    DocumentBuilder documentBuilder;
    ArrayList compositenodes = new ArrayList();
    public TestVisitor(Document documente) throws Exception {
        super();
        this.documentBuilder = new DocumentBuilder(documente);
        documentBuilder.moveToDocumentStart();
    }
    public int visitFieldStart(FieldStart fieldStart) throws Exception {
        String fieldCode = fieldStart.getField().getFieldCode();
        if (fieldCode.contains("NoteStart")) {
            // just move to end mergefield
            documentBuilder.moveToMergeField("NoteEnd",false,false);
            // get current node
            Node end = documentBuilder.getCurrentNode();
            removeSequence(fieldStart, end);
        }
        return VisitorAction.CONTINUE;
    }
    public void removeSequence(Node start, Node end) throws Exception {
        Node curNode = start;
        boolean isFieldEnd = true;
        // Traverse through all the nodes from FieldStart till FieldEnd
        // of User note start tag to reach the node after the field end
        while (curNode != null && isFieldEnd) {
            Node nextNode = curNode.nextPreOrder(curNode.getDocument());
            if (nextNode.getNodeType() == NodeType.FIELD_END) {
                isFieldEnd = false;
            }
            curNode = nextNode;
        }
        // Get the next node after the FieldEnd
        if (curNode != null) {
            curNode = curNode.nextPreOrder(start.getDocument());
        }
        // Remove nodes till the end node is reached
        while (curNode != null && !curNode.equals(end)) {
            // Move to next node
            Node nextNode = curNode.nextPreOrder(start.getDocument());
            // Check whether current contains end node
            if (curNode.isComposite()) {
                CompositeNode curComposite = (CompositeNode) curNode;
                if (!curComposite.getChildNodes().contains(end) &&
                        !curComposite.getChildNodes().contains(start)) {
                    nextNode = curNode.getNextSibling();
                    if (!curNode.getText().equals(ControlChar.CR)) {
                        // ideally cureNode.remove should work here, but it 
                        // does not go to the next visitFieldStart for the next mergefield
                        ((CompositeNode) curNode).removeAllChildren();
                        compositenodes.add(curNode);
                    }
                }
            } else
            {
                curNode.remove();
            }
            curNode = nextNode;
        }
    }
    public int visitFieldEnd(com.aspose.words.FieldEnd fieldEnd) throws Exception
    {
        String fieldCode = fieldEnd.getField().getFieldCode();
        if (fieldCode.contains("NoteEnd")) {
            // remove the merge field for start tag
            documentBuilder.moveToMergeField("NoteStart",false,false);
            documentBuilder.insertHtml("**Text by user**");
        }
        return VisitorAction.CONTINUE;
    }
}