We're sorry Aspose doesn't work properply without JavaScript enabled.

Free Support Forum - aspose.com

DocumentVisitor iteration order

Hi,

I was wondering in what order a Document Visitor enumerates a Document’s elements.

Originally, I was assuming it went through the document tree in the preorder defined by Node.nextPreOrder(), but I’ve got a case where an element that is a preorder successor of some element is not visited after that element, i.e. where a Node successor, such that successor == node.nextPreOrder(null).nextPreOrder(null).nextPreOrder(null), is not visited after node.accept(visitor) is called.

It’d be great if you could shed some light about the inner workings of the visitor implementation in Aspose.Words.

Cheers,
Johannes

Hi

Thanks for your inquiry. You can learn more about Visitor pattern here:
http://en.wikipedia.org/wiki/Visitor_pattern
Hope this information could be useful for you. Please feel free to ask if you need more assistance or information, I will be glad to help you.
Best regards,

Hi,

thank you for your quick answer once again — it is always great to see you’re taking customer care seriously.

I do know the Visitor pattern, though, and I don’t think it specifies the precise iteration algorithm. In essence, it just says that visiting a Composite consists of visiting the composite object itself and visiting each of its Components — in which order is (and can) not be specified (because Composite doesn’t require a Composite’s Components to be ordered).

The reason I’m asking is this: I’ve got a DocumentVisitor whose visit(FieldStart) method may or may not remove the FieldStart object fieldStart it visits, plus any ancestors of fieldStart that become empty this way, and I’d like to carry on visiting the tree right after the removed nodes. What I’m doing is something like this:

public int visit(FieldStart fieldStart) {
    Node previousNode = /** get a node before fieldStart that will not be deleted */
    doSth(fieldStart); // This deletes fieldStart from the document tree;
    previousNode.nextPreOrder(null).accept(this);
    return VisitorAction.STOP;
}

However, contrary to what I expect, the Visitor will never visit previousNode.nextPreOrder(null).nextPreOrder(null).nextPreOrder(null)
which leads me to think that the iteration algorithm does something that I don’t understand right now.

I know this is very little information I’m giving you here, but I’d be very grateful if you could come up with a reason why this algorithm of mine fails. If not, I’ll hack up a minimal example and attach it to this post tomorrow.

Cheers,
Johannes

Hi

Thank you for additional information. I suppose in your case you should use VisitorAction.CONTINUE instead of VisitorAction.STOP. I think the following code will do what you need:

public int visitFieldStart(FieldStart fieldStart) throws Exception
{
    // Get parent node of field start.
    CompositeNode parent = fieldStart.getParentNode();
    // Remove field start.
    fieldStart.remove();
    // Remove ancestors of the removed field start if they are empty.
    while(parent != null && !parent.hasChildNodes())
    {
        CompositeNode grandParent = parent.getParentNode();
        parent.remove();
        parent = grandParent;
    }
    return VisitorAction.CONTINUE;
}

Best regards,

Hi,

thanks again. Your code works well for the simple example I gave you. It doesn’t however work in my specific situation, because I’m really doing more than just remove that node. (Not your fault, obiously — I tried to keep the example simple and apparently left out important details.)

In the end, I resorted to implementing the Internal Visitor pattern:

public abstract class MergeFieldFinder {
    public enum MergeFieldAction {
        GO_ON,
        GO_BACK,
        STOP
    }

    public void visit(Node node) {
        MergeFieldAction goOn = MergeFieldAction.GO_ON;
        Node fallBack = node;
        while(goOn != MergeFieldAction.STOP && node != null) {
            if(isMailMergeField(node)) {
                FieldStart fieldStart = (FieldStart) node;
                goOn = doStuff(fieldStart);
                if(goOn == MergeFieldAction.GO_ON) {
                    fallBack = node;
                } else {
                    node = fallBack;
                }
            }

            node = node.nextPreOrder(null);
        }
    }

    public abstract MergeFieldAction doStuff(FieldStart fieldStart);
}

It’s actually much more primitive than the original solution, but I don’t really need all the features of the DocumentVisitor and this does exactly what I need.

So, thanks again,
Johannes

Hi

It is perfect that you managed to achieve what you need. Please feel free to ask if you have any questions, I will be glad to help you.
Best regards.