com.aspose.words

Class DocumentVisitor

  • java.lang.Object
    • com.aspose.words.DocumentVisitor
public abstract class DocumentVisitor 
extends java.lang.Object

Base class for custom document visitors.

With DocumentVisitor you can define and execute custom operations that require enumeration over the document tree.

For example, Aspose.Words uses DocumentVisitor internally for saving Document in various formats and for other operations like finding fields or bookmarks over a fragment of a document.

To use DocumentVisitor:

  1. Create a class derived from DocumentVisitor.
  2. Override and provide implementations for some or all of the VisitXXX methods to perform some custom operations.
  3. Call Node.accept(com.aspose.words.DocumentVisitor) on the Node that you want to start the enumeration from.

DocumentVisitor provides default implementations for all of the VisitXXX methods to make it easier to create new document visitors as only the methods required for the particular visitor need to be overridden. It is not necessary to override all of the visitor methods.

For more information see the Visitor design pattern.

Example:

Shows how to use a document visitor to print a document's node structure.
public void docStructureToText() throws Exception {
    Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
    DocStructurePrinter visitor = new DocStructurePrinter();

    // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
    // and then traverses all of the node's children in a depth-first manner.
    // The visitor can read and modify each visited node.
    doc.accept(visitor);

    System.out.println(visitor.getText());
}

/// <summary>
/// Traverses a node's tree of child nodes, and creates a map of this tree in the form of a string.
/// </summary>
public static class DocStructurePrinter extends DocumentVisitor {
    public DocStructurePrinter() {
        mAcceptingNodeChildTree = new StringBuilder();
    }

    public String getText() {
        return mAcceptingNodeChildTree.toString();
    }

    /// <summary>
    /// Called when a Document node is encountered.
    /// </summary>
    public int visitDocumentStart(Document doc) {
        int childNodeCount = doc.getChildNodes(NodeType.ANY, true).getCount();

        indentAndAppendLine("[Document start] Child nodes: " + childNodeCount);
        mDocTraversalDepth++;

        // Allow the visitor to continue visiting other nodes.
        return VisitorAction.CONTINUE;
    }

    /// <summary>
    /// Called after all the child nodes of a Document node have been visited.
    /// </summary>
    public int visitDocumentEnd(Document doc) {
        mDocTraversalDepth--;
        indentAndAppendLine("[Document end]");

        return VisitorAction.CONTINUE;
    }

    /// <summary>
    /// Called when a Section node is encountered in the document.
    /// </summary>
    public int visitSectionStart(final Section section) {
        // Get the index of our section within the document
        NodeCollection docSections = section.getDocument().getChildNodes(NodeType.SECTION, false);
        int sectionIndex = docSections.indexOf(section);

        indentAndAppendLine("[Section start] Section index: " + sectionIndex);
        mDocTraversalDepth++;

        return VisitorAction.CONTINUE;
    }

    /// <summary>
    /// Called after all the child nodes of a Section node have been visited.
    /// </summary>
    public int visitSectionEnd(final Section section) {
        mDocTraversalDepth--;
        indentAndAppendLine("[Section end]");

        return VisitorAction.CONTINUE;
    }

    /// <summary>
    /// Called when a Body node is encountered in the document.
    /// </summary>
    public int visitBodyStart(final Body body) {
        int paragraphCount = body.getParagraphs().getCount();
        indentAndAppendLine("[Body start] Paragraphs: " + paragraphCount);
        mDocTraversalDepth++;

        return VisitorAction.CONTINUE;
    }

    /// <summary>
    /// Called after all the child nodes of a Body node have been visited.
    /// </summary>
    public int visitBodyEnd(final Body body) {
        mDocTraversalDepth--;
        indentAndAppendLine("[Body end]");

        return VisitorAction.CONTINUE;
    }

    /// <summary>
    /// Called when a Paragraph node is encountered in the document.
    /// </summary>
    public int visitParagraphStart(final Paragraph paragraph) {
        indentAndAppendLine("[Paragraph start]");
        mDocTraversalDepth++;

        return VisitorAction.CONTINUE;
    }

    /// <summary>
    /// Called after all the child nodes of a Paragraph node have been visited.
    /// </summary>
    public int visitParagraphEnd(final Paragraph paragraph) {
        mDocTraversalDepth--;
        indentAndAppendLine("[Paragraph end]");

        return VisitorAction.CONTINUE;
    }

    /// <summary>
    /// Called when a Run node is encountered in the document.
    /// </summary>
    public int visitRun(final Run run) {
        indentAndAppendLine("[Run] \"" + run.getText() + "\"");

        return VisitorAction.CONTINUE;
    }

    /// <summary>
    /// Called when a SubDocument node is encountered in the document.
    /// </summary>
    public int visitSubDocument(final SubDocument subDocument) {
        indentAndAppendLine("[SubDocument]");

        return VisitorAction.CONTINUE;
    }

    /// <summary>
    /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
    /// </summary>
    /// <param name="text"></param>
    private void indentAndAppendLine(final String text) {
        for (int i = 0; i < mDocTraversalDepth; i++) {
            mAcceptingNodeChildTree.append("|  ");
        }

        mAcceptingNodeChildTree.append(text + "\r\n");
    }

    private int mDocTraversalDepth;
    private StringBuilder mAcceptingNodeChildTree;
}

Method Summary
intvisitAbsolutePositionTab(AbsolutePositionTab tab)
Called when a AbsolutePositionTab node is encountered in the document.
intvisitBodyEnd(Body body)
Called when enumeration of the main text story in a section has ended.
intvisitBodyStart(Body body)
Called when enumeration of the main text story in a section has started.
intvisitBookmarkEnd(BookmarkEnd bookmarkEnd)
Called when an end of a bookmark is encountered in the document.
intvisitBookmarkStart(BookmarkStart bookmarkStart)
Called when a start of a bookmark is encountered in the document.
intvisitBuildingBlockEnd(BuildingBlock block)
Called when enumeration of a building block has ended.
intvisitBuildingBlockStart(BuildingBlock block)
Called when enumeration of a building block has started.
intvisitCellEnd(Cell cell)
Called when enumeration of a table cell has ended.
intvisitCellStart(Cell cell)
Called when enumeration of a table cell has started.
intvisitCommentEnd(Comment comment)
Called when enumeration of a comment text has ended.
intvisitCommentRangeEnd(CommentRangeEnd commentRangeEnd)
Called when the end of a commented range of text is encountered.
intvisitCommentRangeStart(CommentRangeStart commentRangeStart)
Called when the start of a commented range of text is encountered.
intvisitCommentStart(Comment comment)
Called when enumeration of a comment text has started.
intvisitDocumentEnd(Document doc)
Called when enumeration of the document has finished.
intvisitDocumentStart(Document doc)
Called when enumeration of the document has started.
intvisitEditableRangeEnd(EditableRangeEnd editableRangeEnd)
Called when an end of an editable range is encountered in the document.
intvisitEditableRangeStart(EditableRangeStart editableRangeStart)
Called when a start of an editable range is encountered in the document.
intvisitFieldEnd(FieldEnd fieldEnd)
Called when a field ends in the document.
intvisitFieldSeparator(FieldSeparator fieldSeparator)
Called when a field separator is encountered in the document.
intvisitFieldStart(FieldStart fieldStart)
Called when a field starts in the document.
intvisitFootnoteEnd(Footnote footnote)
Called when enumeration of a footnote or endnote text has ended.
intvisitFootnoteStart(Footnote footnote)
Called when enumeration of a footnote or endnote text has started.
intvisitFormField(FormField formField)
Called when a form field is encountered in the document.
intvisitGlossaryDocumentEnd(GlossaryDocument glossary)
Called when enumeration of a glossary document has ended.
intvisitGlossaryDocumentStart(GlossaryDocument glossary)
Called when enumeration of a glossary document has started.
intvisitGroupShapeEnd(GroupShape groupShape)
Called when enumeration of a group shape has ended.
intvisitGroupShapeStart(GroupShape groupShape)
Called when enumeration of a group shape has started.
intvisitHeaderFooterEnd(HeaderFooter headerFooter)
Called when enumeration of a header or footer in a section has ended.
intvisitHeaderFooterStart(HeaderFooter headerFooter)
Called when enumeration of a header or footer in a section has started.
intvisitOfficeMathEnd(OfficeMath officeMath)
Called when enumeration of a Office Math object has ended.
intvisitOfficeMathStart(OfficeMath officeMath)
Called when enumeration of a Office Math object has started.
intvisitParagraphEnd(Paragraph paragraph)
Called when enumeration of a paragraph has ended.
intvisitParagraphStart(Paragraph paragraph)
Called when enumeration of a paragraph has started.
intvisitRowEnd(Row row)
Called when enumeration of a table row has ended.
intvisitRowStart(Row row)
Called when enumeration of a table row has started.
intvisitRun(Run run)
Called when a run of text in the is encountered.
intvisitSectionEnd(Section section)
Called when enumeration of a section has ended.
intvisitSectionStart(Section section)
Called when enumeration of a section has started.
intvisitShapeEnd(Shape shape)
Called when enumeration of a shape has ended.
intvisitShapeStart(Shape shape)
Called when enumeration of a shape has started.
intvisitSmartTagEnd(SmartTag smartTag)
Called when enumeration of a smart tag has ended.
intvisitSmartTagStart(SmartTag smartTag)
Called when enumeration of a smart tag has started.
intvisitSpecialChar(SpecialChar specialChar)
Called when a SpecialChar node is encountered in the document.
intvisitStructuredDocumentTagEnd(StructuredDocumentTag sdt)
Called when enumeration of a structured document tag has ended.
intvisitStructuredDocumentTagRangeEnd(StructuredDocumentTagRangeEnd sdtRangeEnd)
intvisitStructuredDocumentTagRangeStart(StructuredDocumentTagRangeStart sdtRangeStart)
intvisitStructuredDocumentTagStart(StructuredDocumentTag sdt)
Called when enumeration of a structured document tag has started.
intvisitSubDocument(SubDocument subDocument)
Called when a subDocument is encountered.
intvisitTableEnd(Table table)
Called when enumeration of a table has ended.
intvisitTableStart(Table table)
Called when enumeration of a table has started.
 

    • Method Detail

      • visitAbsolutePositionTab

        public int visitAbsolutePositionTab(AbsolutePositionTab tab)
                                    throws java.lang.Exception
        Called when a AbsolutePositionTab node is encountered in the document.
        Parameters:
        tab - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to process absolute position tab characters with a document visitor.
        public void documentToTxt() throws Exception
        {
            Document doc = new Document(getMyDir() + "Absolute position tab.docx");
        
            // Extract the text contents of our document by accepting this custom document visitor.
            DocTextExtractor myDocTextExtractor = new DocTextExtractor();
            doc.getFirstSection().getBody().accept(myDocTextExtractor);
        
            // The absolute position tab, which has no equivalent in string form, has been explicitly converted to a tab character.
            Assert.assertEquals("Before AbsolutePositionTab\tAfter AbsolutePositionTab", myDocTextExtractor.getText());
        
            // An AbsolutePositionTab can accept a DocumentVisitor by itself too.
            AbsolutePositionTab absPositionTab = (AbsolutePositionTab)doc.getFirstSection().getBody().getFirstParagraph().getChild(NodeType.SPECIAL_CHAR, 0, true);
        
            myDocTextExtractor = new DocTextExtractor();
            absPositionTab.accept(myDocTextExtractor);
        
            Assert.assertEquals("\t", myDocTextExtractor.getText());
        }
        
        /// <summary>
        /// Collects the text contents of all runs in the visited document, and represents all absolute tab characters as ordinary tabs.
        /// </summary>
        public static class DocTextExtractor extends DocumentVisitor
        {
            public DocTextExtractor()
            {
                mBuilder = new StringBuilder();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                appendText(run.getText());
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when an AbsolutePositionTab node is encountered in the document.
            /// </summary>
            public int visitAbsolutePositionTab(final AbsolutePositionTab tab) {
                mBuilder.append("\t");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Adds text to the current output. Honors the enabled/disabled output flag.
            /// </summary>
            public void appendText(final String text) {
                mBuilder.append(text);
            }
        
            /// <summary>
            /// Plain text of the document that was accumulated by the visitor.
            /// </summary>
            public String getText() {
                return mBuilder.toString();
            }
        
            private StringBuilder mBuilder;
        }
      • visitBodyEnd

        public int visitBodyEnd(Body body)
                        throws java.lang.Exception
        Called when enumeration of the main text story in a section has ended.
        Parameters:
        body - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to use a document visitor to print a document's node structure.
        public void docStructureToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            DocStructurePrinter visitor = new DocStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's tree of child nodes, and creates a map of this tree in the form of a string.
        /// </summary>
        public static class DocStructurePrinter extends DocumentVisitor {
            public DocStructurePrinter() {
                mAcceptingNodeChildTree = new StringBuilder();
            }
        
            public String getText() {
                return mAcceptingNodeChildTree.toString();
            }
        
            /// <summary>
            /// Called when a Document node is encountered.
            /// </summary>
            public int visitDocumentStart(Document doc) {
                int childNodeCount = doc.getChildNodes(NodeType.ANY, true).getCount();
        
                indentAndAppendLine("[Document start] Child nodes: " + childNodeCount);
                mDocTraversalDepth++;
        
                // Allow the visitor to continue visiting other nodes.
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Document node have been visited.
            /// </summary>
            public int visitDocumentEnd(Document doc) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Document end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Section node is encountered in the document.
            /// </summary>
            public int visitSectionStart(final Section section) {
                // Get the index of our section within the document
                NodeCollection docSections = section.getDocument().getChildNodes(NodeType.SECTION, false);
                int sectionIndex = docSections.indexOf(section);
        
                indentAndAppendLine("[Section start] Section index: " + sectionIndex);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Section node have been visited.
            /// </summary>
            public int visitSectionEnd(final Section section) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Section end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Body node is encountered in the document.
            /// </summary>
            public int visitBodyStart(final Body body) {
                int paragraphCount = body.getParagraphs().getCount();
                indentAndAppendLine("[Body start] Paragraphs: " + paragraphCount);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Body node have been visited.
            /// </summary>
            public int visitBodyEnd(final Body body) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Body end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Paragraph node is encountered in the document.
            /// </summary>
            public int visitParagraphStart(final Paragraph paragraph) {
                indentAndAppendLine("[Paragraph start]");
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Paragraph node have been visited.
            /// </summary>
            public int visitParagraphEnd(final Paragraph paragraph) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Paragraph end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SubDocument node is encountered in the document.
            /// </summary>
            public int visitSubDocument(final SubDocument subDocument) {
                indentAndAppendLine("[SubDocument]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mAcceptingNodeChildTree.append("|  ");
                }
        
                mAcceptingNodeChildTree.append(text + "\r\n");
            }
        
            private int mDocTraversalDepth;
            private StringBuilder mAcceptingNodeChildTree;
        }
      • visitBodyStart

        public int visitBodyStart(Body body)
                          throws java.lang.Exception
        Called when enumeration of the main text story in a section has started.
        Parameters:
        body - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to use a document visitor to print a document's node structure.
        public void docStructureToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            DocStructurePrinter visitor = new DocStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's tree of child nodes, and creates a map of this tree in the form of a string.
        /// </summary>
        public static class DocStructurePrinter extends DocumentVisitor {
            public DocStructurePrinter() {
                mAcceptingNodeChildTree = new StringBuilder();
            }
        
            public String getText() {
                return mAcceptingNodeChildTree.toString();
            }
        
            /// <summary>
            /// Called when a Document node is encountered.
            /// </summary>
            public int visitDocumentStart(Document doc) {
                int childNodeCount = doc.getChildNodes(NodeType.ANY, true).getCount();
        
                indentAndAppendLine("[Document start] Child nodes: " + childNodeCount);
                mDocTraversalDepth++;
        
                // Allow the visitor to continue visiting other nodes.
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Document node have been visited.
            /// </summary>
            public int visitDocumentEnd(Document doc) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Document end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Section node is encountered in the document.
            /// </summary>
            public int visitSectionStart(final Section section) {
                // Get the index of our section within the document
                NodeCollection docSections = section.getDocument().getChildNodes(NodeType.SECTION, false);
                int sectionIndex = docSections.indexOf(section);
        
                indentAndAppendLine("[Section start] Section index: " + sectionIndex);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Section node have been visited.
            /// </summary>
            public int visitSectionEnd(final Section section) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Section end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Body node is encountered in the document.
            /// </summary>
            public int visitBodyStart(final Body body) {
                int paragraphCount = body.getParagraphs().getCount();
                indentAndAppendLine("[Body start] Paragraphs: " + paragraphCount);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Body node have been visited.
            /// </summary>
            public int visitBodyEnd(final Body body) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Body end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Paragraph node is encountered in the document.
            /// </summary>
            public int visitParagraphStart(final Paragraph paragraph) {
                indentAndAppendLine("[Paragraph start]");
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Paragraph node have been visited.
            /// </summary>
            public int visitParagraphEnd(final Paragraph paragraph) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Paragraph end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SubDocument node is encountered in the document.
            /// </summary>
            public int visitSubDocument(final SubDocument subDocument) {
                indentAndAppendLine("[SubDocument]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mAcceptingNodeChildTree.append("|  ");
                }
        
                mAcceptingNodeChildTree.append(text + "\r\n");
            }
        
            private int mDocTraversalDepth;
            private StringBuilder mAcceptingNodeChildTree;
        }
      • visitBookmarkEnd

        public int visitBookmarkEnd(BookmarkEnd bookmarkEnd)
                            throws java.lang.Exception
        Called when an end of a bookmark is encountered in the document.
        Parameters:
        bookmarkEnd - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to add bookmarks and update their contents.
        public void createUpdateAndPrintBookmarks() throws Exception
        {
            // Create a document with three bookmarks, then use a custom document visitor implementation to print their contents.
            Document doc = createDocumentWithBookmarks(3);
            BookmarkCollection bookmarks = doc.getRange().getBookmarks();
        
            printAllBookmarkInfo(bookmarks);
        
            // Bookmarks can be accessed in the bookmark collection by index or name, and their names can be updated.
            bookmarks.get(0).setName("{bookmarks[0].Name}_NewName");
            bookmarks.get("MyBookmark_2").setText("Updated text contents of {bookmarks[1].Name}");
        
            // Print all bookmarks again to see updated values.
            printAllBookmarkInfo(bookmarks);
        }
        
        /// <summary>
        /// Create a document with a given number of bookmarks.
        /// </summary>
        private static Document createDocumentWithBookmarks(int numberOfBookmarks) throws Exception
        {
            Document doc = new Document();
            DocumentBuilder builder = new DocumentBuilder(doc);
        
            for (int i = 1; i <= numberOfBookmarks; i++)
            {
                String bookmarkName = "MyBookmark_" + i;
        
                builder.write("Text before bookmark.");
                builder.startBookmark(bookmarkName);
                builder.write(MessageFormat.format("Text inside {0}.", bookmarkName));
                builder.endBookmark(bookmarkName);
                builder.writeln("Text after bookmark.");
            }
        
            return doc;
        }
        
        /// <summary>
        /// Use an iterator and a visitor to print info of every bookmark in the collection.
        /// </summary>
        private static void printAllBookmarkInfo(BookmarkCollection bookmarks) throws Exception
        {
            BookmarkInfoPrinter bookmarkVisitor = new BookmarkInfoPrinter();
        
            // Get each bookmark in the collection to accept a visitor that will print its contents.
            Iterator<Bookmark> enumerator = bookmarks.iterator();
        
            while (enumerator.hasNext()) {
                Bookmark currentBookmark = enumerator.next();
        
                    if (currentBookmark != null)
                    {
                    currentBookmark.getBookmarkStart().accept(bookmarkVisitor);
                    currentBookmark.getBookmarkEnd().accept(bookmarkVisitor);
        
                    System.out.println(currentBookmark.getBookmarkStart().getText());
                }
            }
        }
        
        /// <summary>
        /// Prints contents of every visited bookmark to the console.
        /// </summary>
        public static class BookmarkInfoPrinter extends DocumentVisitor {
            public int visitBookmarkStart(BookmarkStart bookmarkStart) throws Exception {
                System.out.println(MessageFormat.format("BookmarkStart name: \"{0}\", Content: \"{1}\"", bookmarkStart.getName(),
                        bookmarkStart.getBookmark().getText()));
                return VisitorAction.CONTINUE;
            }
        
            public int visitBookmarkEnd(BookmarkEnd bookmarkEnd) {
                System.out.println(MessageFormat.format("BookmarkEnd name: \"{0}\"", bookmarkEnd.getName()));
                return VisitorAction.CONTINUE;
            }
        }
      • visitBookmarkStart

        public int visitBookmarkStart(BookmarkStart bookmarkStart)
                              throws java.lang.Exception
        Called when a start of a bookmark is encountered in the document.
        Parameters:
        bookmarkStart - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to add bookmarks and update their contents.
        public void createUpdateAndPrintBookmarks() throws Exception
        {
            // Create a document with three bookmarks, then use a custom document visitor implementation to print their contents.
            Document doc = createDocumentWithBookmarks(3);
            BookmarkCollection bookmarks = doc.getRange().getBookmarks();
        
            printAllBookmarkInfo(bookmarks);
        
            // Bookmarks can be accessed in the bookmark collection by index or name, and their names can be updated.
            bookmarks.get(0).setName("{bookmarks[0].Name}_NewName");
            bookmarks.get("MyBookmark_2").setText("Updated text contents of {bookmarks[1].Name}");
        
            // Print all bookmarks again to see updated values.
            printAllBookmarkInfo(bookmarks);
        }
        
        /// <summary>
        /// Create a document with a given number of bookmarks.
        /// </summary>
        private static Document createDocumentWithBookmarks(int numberOfBookmarks) throws Exception
        {
            Document doc = new Document();
            DocumentBuilder builder = new DocumentBuilder(doc);
        
            for (int i = 1; i <= numberOfBookmarks; i++)
            {
                String bookmarkName = "MyBookmark_" + i;
        
                builder.write("Text before bookmark.");
                builder.startBookmark(bookmarkName);
                builder.write(MessageFormat.format("Text inside {0}.", bookmarkName));
                builder.endBookmark(bookmarkName);
                builder.writeln("Text after bookmark.");
            }
        
            return doc;
        }
        
        /// <summary>
        /// Use an iterator and a visitor to print info of every bookmark in the collection.
        /// </summary>
        private static void printAllBookmarkInfo(BookmarkCollection bookmarks) throws Exception
        {
            BookmarkInfoPrinter bookmarkVisitor = new BookmarkInfoPrinter();
        
            // Get each bookmark in the collection to accept a visitor that will print its contents.
            Iterator<Bookmark> enumerator = bookmarks.iterator();
        
            while (enumerator.hasNext()) {
                Bookmark currentBookmark = enumerator.next();
        
                    if (currentBookmark != null)
                    {
                    currentBookmark.getBookmarkStart().accept(bookmarkVisitor);
                    currentBookmark.getBookmarkEnd().accept(bookmarkVisitor);
        
                    System.out.println(currentBookmark.getBookmarkStart().getText());
                }
            }
        }
        
        /// <summary>
        /// Prints contents of every visited bookmark to the console.
        /// </summary>
        public static class BookmarkInfoPrinter extends DocumentVisitor {
            public int visitBookmarkStart(BookmarkStart bookmarkStart) throws Exception {
                System.out.println(MessageFormat.format("BookmarkStart name: \"{0}\", Content: \"{1}\"", bookmarkStart.getName(),
                        bookmarkStart.getBookmark().getText()));
                return VisitorAction.CONTINUE;
            }
        
            public int visitBookmarkEnd(BookmarkEnd bookmarkEnd) {
                System.out.println(MessageFormat.format("BookmarkEnd name: \"{0}\"", bookmarkEnd.getName()));
                return VisitorAction.CONTINUE;
            }
        }
      • visitBuildingBlockEnd

        public int visitBuildingBlockEnd(BuildingBlock block)
                                 throws java.lang.Exception
        Called when enumeration of a building block has ended.

        Note: A building block node and its children are not visited when you execute a Visitor over a Document. If you want to execute a Visitor over a building block, you need to execute the visitor over GlossaryDocument or call BuildingBlock.accept(com.aspose.words.DocumentVisitor).

        Parameters:
        block - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows ways of accessing building blocks in a glossary document.
        public void glossaryDocument() throws Exception {
            Document doc = new Document();
            GlossaryDocument glossaryDoc = new GlossaryDocument();
        
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 1"));
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 2"));
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 3"));
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 4"));
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 5"));
        
            Assert.assertEquals(glossaryDoc.getBuildingBlocks().getCount(), 5);
        
            doc.setGlossaryDocument(glossaryDoc);
        
            // There are various ways of accessing building blocks.
            // 1 -  Get the first/last building blocks in the collection:
            Assert.assertEquals("Block 1", glossaryDoc.getFirstBuildingBlock().getName());
            Assert.assertEquals("Block 5", glossaryDoc.getLastBuildingBlock().getName());
        
            // 2 -  Get a building block by index:
            Assert.assertEquals("Block 2", glossaryDoc.getBuildingBlocks().get(1).getName());
            Assert.assertEquals("Block 3", glossaryDoc.getBuildingBlocks().toArray()[2].getName());
        
            // 3 -  Get the first building block that matches a gallery, name and category:
            Assert.assertEquals("Block 4", 
                glossaryDoc.getBuildingBlock(BuildingBlockGallery.ALL, "(Empty Category)", "Block 4").getName());
        
            // We will do that using a custom visitor,
            // which will give every BuildingBlock in the GlossaryDocument a unique GUID
            GlossaryDocVisitor visitor = new GlossaryDocVisitor();
            glossaryDoc.accept(visitor);
        
            System.out.println(visitor.getText());
        
            // When we open this document using Microsoft Word,
            // we can find the building blocks via Insert -> Quick Parts -> Building Blocks Organizer.
            doc.save(getArtifactsDir() + "BuildingBlocks.GlossaryDocument.dotx"); 
        }
        
        public static BuildingBlock createNewBuildingBlock(final GlossaryDocument glossaryDoc, final String buildingBlockName) {
            BuildingBlock buildingBlock = new BuildingBlock(glossaryDoc);
            buildingBlock.setName(buildingBlockName);
        
            return buildingBlock;
        }
        
        /// <summary>
        /// Gives each building block in a visited glossary document a unique GUID, and stores the GUID-building block pairs in a dictionary.
        /// </summary>
        public static class GlossaryDocVisitor extends DocumentVisitor {
            public GlossaryDocVisitor() {
                mBlocksByGuid = new HashMap<>();
                mBuilder = new StringBuilder();
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            public HashMap<UUID, BuildingBlock> getDictionary() {
                return mBlocksByGuid;
            }
        
            public int visitGlossaryDocumentStart(final GlossaryDocument glossary) {
                mBuilder.append("Glossary document found!\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitGlossaryDocumentEnd(final GlossaryDocument glossary) {
                mBuilder.append("Reached end of glossary!\n");
                mBuilder.append("BuildingBlocks found: " + mBlocksByGuid.size() + "\r\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitBuildingBlockStart(final BuildingBlock block) {
                block.setGuid(UUID.randomUUID());
                mBlocksByGuid.put(block.getGuid(), block);
                return VisitorAction.CONTINUE;
            }
        
            public int visitBuildingBlockEnd(final BuildingBlock block) {
                mBuilder.append("\tVisited block \"" + block.getName() + "\"" + "\r\n");
                mBuilder.append("\t Type: " + block.getType() + "\r\n");
                mBuilder.append("\t Gallery: " + block.getGallery() + "\r\n");
                mBuilder.append("\t Behavior: " + block.getBehavior() + "\r\n");
                mBuilder.append("\t Description: " + block.getDescription() + "\r\n");
        
                return VisitorAction.CONTINUE;
            }
        
            private HashMap<UUID, BuildingBlock> mBlocksByGuid;
            private StringBuilder mBuilder;
        }
      • visitBuildingBlockStart

        public int visitBuildingBlockStart(BuildingBlock block)
                                   throws java.lang.Exception
        Called when enumeration of a building block has started.

        Note: A building block node and its children are not visited when you execute a Visitor over a Document. If you want to execute a Visitor over a building block, you need to execute the visitor over GlossaryDocument or call BuildingBlock.accept(com.aspose.words.DocumentVisitor).

        Parameters:
        block - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows ways of accessing building blocks in a glossary document.
        public void glossaryDocument() throws Exception {
            Document doc = new Document();
            GlossaryDocument glossaryDoc = new GlossaryDocument();
        
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 1"));
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 2"));
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 3"));
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 4"));
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 5"));
        
            Assert.assertEquals(glossaryDoc.getBuildingBlocks().getCount(), 5);
        
            doc.setGlossaryDocument(glossaryDoc);
        
            // There are various ways of accessing building blocks.
            // 1 -  Get the first/last building blocks in the collection:
            Assert.assertEquals("Block 1", glossaryDoc.getFirstBuildingBlock().getName());
            Assert.assertEquals("Block 5", glossaryDoc.getLastBuildingBlock().getName());
        
            // 2 -  Get a building block by index:
            Assert.assertEquals("Block 2", glossaryDoc.getBuildingBlocks().get(1).getName());
            Assert.assertEquals("Block 3", glossaryDoc.getBuildingBlocks().toArray()[2].getName());
        
            // 3 -  Get the first building block that matches a gallery, name and category:
            Assert.assertEquals("Block 4", 
                glossaryDoc.getBuildingBlock(BuildingBlockGallery.ALL, "(Empty Category)", "Block 4").getName());
        
            // We will do that using a custom visitor,
            // which will give every BuildingBlock in the GlossaryDocument a unique GUID
            GlossaryDocVisitor visitor = new GlossaryDocVisitor();
            glossaryDoc.accept(visitor);
        
            System.out.println(visitor.getText());
        
            // When we open this document using Microsoft Word,
            // we can find the building blocks via Insert -> Quick Parts -> Building Blocks Organizer.
            doc.save(getArtifactsDir() + "BuildingBlocks.GlossaryDocument.dotx"); 
        }
        
        public static BuildingBlock createNewBuildingBlock(final GlossaryDocument glossaryDoc, final String buildingBlockName) {
            BuildingBlock buildingBlock = new BuildingBlock(glossaryDoc);
            buildingBlock.setName(buildingBlockName);
        
            return buildingBlock;
        }
        
        /// <summary>
        /// Gives each building block in a visited glossary document a unique GUID, and stores the GUID-building block pairs in a dictionary.
        /// </summary>
        public static class GlossaryDocVisitor extends DocumentVisitor {
            public GlossaryDocVisitor() {
                mBlocksByGuid = new HashMap<>();
                mBuilder = new StringBuilder();
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            public HashMap<UUID, BuildingBlock> getDictionary() {
                return mBlocksByGuid;
            }
        
            public int visitGlossaryDocumentStart(final GlossaryDocument glossary) {
                mBuilder.append("Glossary document found!\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitGlossaryDocumentEnd(final GlossaryDocument glossary) {
                mBuilder.append("Reached end of glossary!\n");
                mBuilder.append("BuildingBlocks found: " + mBlocksByGuid.size() + "\r\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitBuildingBlockStart(final BuildingBlock block) {
                block.setGuid(UUID.randomUUID());
                mBlocksByGuid.put(block.getGuid(), block);
                return VisitorAction.CONTINUE;
            }
        
            public int visitBuildingBlockEnd(final BuildingBlock block) {
                mBuilder.append("\tVisited block \"" + block.getName() + "\"" + "\r\n");
                mBuilder.append("\t Type: " + block.getType() + "\r\n");
                mBuilder.append("\t Gallery: " + block.getGallery() + "\r\n");
                mBuilder.append("\t Behavior: " + block.getBehavior() + "\r\n");
                mBuilder.append("\t Description: " + block.getDescription() + "\r\n");
        
                return VisitorAction.CONTINUE;
            }
        
            private HashMap<UUID, BuildingBlock> mBlocksByGuid;
            private StringBuilder mBuilder;
        }
      • visitCellEnd

        public int visitCellEnd(Cell cell)
                        throws java.lang.Exception
        Called when enumeration of a table cell has ended.
        Parameters:
        cell - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Implements the Visitor Pattern to remove all content formatted as hidden from the document.
        public void removeHiddenContentFromDocument() throws Exception {
            // Open the document we want to remove hidden content from
            Document doc = new Document(getMyDir() + "Hidden content.docx");
        
            // Create an object that inherits from the DocumentVisitor class
            RemoveHiddenContentVisitor hiddenContentRemover = new RemoveHiddenContentVisitor();
        
            // This is the well known Visitor pattern. Get the model to accept a visitor
            // The model will iterate through itself by calling the corresponding methods
            // on the visitor object (this is called visiting)
        
            // We can run it over the entire the document like so
            doc.accept(hiddenContentRemover);
        
            // Or we can run it on only a specific node
            Paragraph para = (Paragraph) doc.getChild(NodeType.PARAGRAPH, 4, true);
            para.accept(hiddenContentRemover);
        
            // Or over a different type of node like below
            Table table = (Table) doc.getChild(NodeType.TABLE, 0, true);
            table.accept(hiddenContentRemover);
        
            doc.save(getArtifactsDir() + "Font.RemoveHiddenContentFromDocument.docx");
        }
        
        /**
         * This class when executed will remove all hidden content from the Document. Implemented as a Visitor.
         */
        private class RemoveHiddenContentVisitor extends DocumentVisitor {
            /**
             * Called when a FieldStart node is encountered in the document.
             */
            public int visitFieldStart(final FieldStart fieldStart) throws Exception {
                // If this node is hidden, then remove it
                if (fieldStart.getFont().getHidden()) {
                    fieldStart.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldEnd node is encountered in the document.
             */
            public int visitFieldEnd(final FieldEnd fieldEnd) throws Exception {
                if (fieldEnd.getFont().getHidden()) {
                    fieldEnd.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldSeparator node is encountered in the document.
             */
            public int visitFieldSeparator(final FieldSeparator fieldSeparator) throws Exception {
                if (fieldSeparator.getFont().getHidden()) {
                    fieldSeparator.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Run node is encountered in the document.
             */
            public int visitRun(final Run run) throws Exception {
                if (run.getFont().getHidden()) {
                    run.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Paragraph node is encountered in the document.
             */
            public int visitParagraphStart(final Paragraph paragraph) throws Exception {
                if (paragraph.getParagraphBreakFont().getHidden()) {
                    paragraph.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FormField is encountered in the document.
             */
            public int visitFormField(final FormField field) throws Exception {
                if (field.getFont().getHidden()) {
                    field.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a GroupShape is encountered in the document.
             */
            public int visitGroupShapeStart(final GroupShape groupShape) throws Exception {
                if (groupShape.getFont().getHidden()) {
                    groupShape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Shape is encountered in the document.
             */
            public int visitShapeStart(final Shape shape) throws Exception {
                if (shape.getFont().getHidden()) {
                    shape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Comment is encountered in the document.
             */
            public int visitCommentStart(final Comment comment) throws Exception {
                if (comment.getFont().getHidden()) {
                    comment.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Footnote is encountered in the document.
             */
            public int visitFootnoteStart(final Footnote footnote) throws Exception {
                if (footnote.getFont().getHidden()) {
                    footnote.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SpecialCharacter is encountered in the document.
            /// </summary>
            public /*override*/ /*VisitorAction*/int visitSpecialChar(SpecialChar specialChar) {
                if (specialChar.getFont().getHidden())
                    specialChar.remove();
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Table node is ended in the document.
             */
            public int visitTableEnd(final Table table) {
                // At the moment there is no way to tell if a particular Table/Row/Cell is hidden.
                // Instead, if the content of a table is hidden, then all inline child nodes of the table should be
                // hidden and thus removed by previous visits as well. This will result in the container being empty
                // so if this is the case we know to remove the table node.
                //
                // Note that a table which is not hidden but simply has no content will not be affected by this algorithm,
                // as technically they are not completely empty (for example a properly formed Cell will have at least 
                // an empty paragraph in it)
                if (!table.hasChildNodes()) {
                    table.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Cell node is ended in the document.
             */
            public int visitCellEnd(final Cell cell) {
                if (!cell.hasChildNodes() && cell.getParentNode() != null) {
                    cell.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Row node is ended in the document.
             */
            public int visitRowEnd(final Row row) {
                if (!row.hasChildNodes() && row.getParentNode() != null) {
                    row.remove();
                }
        
                return VisitorAction.CONTINUE;
            }

        Example:

        Shows how to print the node structure of every table in a document.
        public void tableToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            TableStructurePrinter visitor = new TableStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered Table nodes and their children.
        /// </summary>
        public static class TableStructurePrinter extends DocumentVisitor {
            public TableStructurePrinter() {
                mVisitedTables = new StringBuilder();
                mVisitorIsInsideTable = false;
            }
        
            public String getText() {
                return mVisitedTables.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// Runs that are not within tables are not recorded.
            /// </summary>
            public /*override*/ /*VisitorAction*/int visitRun(Run run) {
                if (mVisitorIsInsideTable) indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Table is encountered in the document.
            /// </summary>
            public int visitTableStart(final Table table) {
                int rows = 0;
                int columns = 0;
        
                if (table.getRows().getCount() > 0) {
                    rows = table.getRows().getCount();
                    columns = table.getFirstRow().getCount();
                }
        
                indentAndAppendLine("[Table start] Size: " + rows + "x" + columns);
                mDocTraversalDepth++;
                mVisitorIsInsideTable = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Table node have been visited.
            /// </summary>
            public int visitTableEnd(final Table table) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Table end]");
                mVisitorIsInsideTable = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Row node is encountered in the document.
            /// </summary>
            public int visitRowStart(final Row row) {
                String rowContents = row.getText().replaceAll("\\u0007", ", ").replaceAll(", , ", "");
                int rowWidth = row.indexOf(row.getLastCell()) + 1;
                int rowIndex = row.getParentTable().indexOf(row);
                String rowStatusInTable = row.isFirstRow() && row.isLastRow() ? "only" : row.isFirstRow() ? "first" : row.isLastRow() ? "last" : "";
                if (!"".equals(rowStatusInTable)) {
                    rowStatusInTable = MessageFormat.format(", the {0} row in this table,", rowStatusInTable);
                }
        
                indentAndAppendLine(MessageFormat.format("[Row start] Row #{0}{1} width {2}, \"{3}\"", ++rowIndex, rowStatusInTable, rowWidth, rowContents));
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Row node have been visited.
            /// </summary>
            public int visitRowEnd(final Row row) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Row end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Cell node is encountered in the document.
            /// </summary>
            public int visitCellStart(final Cell cell) {
                Row row = cell.getParentRow();
                Table table = row.getParentTable();
                String cellStatusInRow = cell.isFirstCell() && cell.isLastCell() ? "only" : cell.isFirstCell() ? "first" : cell.isLastCell() ? "last" : "";
                if (!"".equals(cellStatusInRow)) {
                    cellStatusInRow = MessageFormat.format(", the {0} cell in this row", cellStatusInRow);
                }
        
                indentAndAppendLine(MessageFormat.format("[Cell start] Row {0}, Col {1}{2}", table.indexOf(row) + 1, row.indexOf(cell) + 1, cellStatusInRow));
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Cell node have been visited.
            /// </summary>
            public int visitCellEnd(final Cell cell) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Cell end]");
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder, and indent it depending on how deep the visitor is
            /// into the current table's tree of child nodes.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mVisitedTables.append("|  ");
                }
        
                mVisitedTables.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideTable;
            private int mDocTraversalDepth;
            private /*final*/ StringBuilder mVisitedTables;
        }
      • visitCellStart

        public int visitCellStart(Cell cell)
                          throws java.lang.Exception
        Called when enumeration of a table cell has started.
        Parameters:
        cell - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every table in a document.
        public void tableToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            TableStructurePrinter visitor = new TableStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered Table nodes and their children.
        /// </summary>
        public static class TableStructurePrinter extends DocumentVisitor {
            public TableStructurePrinter() {
                mVisitedTables = new StringBuilder();
                mVisitorIsInsideTable = false;
            }
        
            public String getText() {
                return mVisitedTables.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// Runs that are not within tables are not recorded.
            /// </summary>
            public /*override*/ /*VisitorAction*/int visitRun(Run run) {
                if (mVisitorIsInsideTable) indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Table is encountered in the document.
            /// </summary>
            public int visitTableStart(final Table table) {
                int rows = 0;
                int columns = 0;
        
                if (table.getRows().getCount() > 0) {
                    rows = table.getRows().getCount();
                    columns = table.getFirstRow().getCount();
                }
        
                indentAndAppendLine("[Table start] Size: " + rows + "x" + columns);
                mDocTraversalDepth++;
                mVisitorIsInsideTable = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Table node have been visited.
            /// </summary>
            public int visitTableEnd(final Table table) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Table end]");
                mVisitorIsInsideTable = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Row node is encountered in the document.
            /// </summary>
            public int visitRowStart(final Row row) {
                String rowContents = row.getText().replaceAll("\\u0007", ", ").replaceAll(", , ", "");
                int rowWidth = row.indexOf(row.getLastCell()) + 1;
                int rowIndex = row.getParentTable().indexOf(row);
                String rowStatusInTable = row.isFirstRow() && row.isLastRow() ? "only" : row.isFirstRow() ? "first" : row.isLastRow() ? "last" : "";
                if (!"".equals(rowStatusInTable)) {
                    rowStatusInTable = MessageFormat.format(", the {0} row in this table,", rowStatusInTable);
                }
        
                indentAndAppendLine(MessageFormat.format("[Row start] Row #{0}{1} width {2}, \"{3}\"", ++rowIndex, rowStatusInTable, rowWidth, rowContents));
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Row node have been visited.
            /// </summary>
            public int visitRowEnd(final Row row) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Row end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Cell node is encountered in the document.
            /// </summary>
            public int visitCellStart(final Cell cell) {
                Row row = cell.getParentRow();
                Table table = row.getParentTable();
                String cellStatusInRow = cell.isFirstCell() && cell.isLastCell() ? "only" : cell.isFirstCell() ? "first" : cell.isLastCell() ? "last" : "";
                if (!"".equals(cellStatusInRow)) {
                    cellStatusInRow = MessageFormat.format(", the {0} cell in this row", cellStatusInRow);
                }
        
                indentAndAppendLine(MessageFormat.format("[Cell start] Row {0}, Col {1}{2}", table.indexOf(row) + 1, row.indexOf(cell) + 1, cellStatusInRow));
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Cell node have been visited.
            /// </summary>
            public int visitCellEnd(final Cell cell) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Cell end]");
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder, and indent it depending on how deep the visitor is
            /// into the current table's tree of child nodes.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mVisitedTables.append("|  ");
                }
        
                mVisitedTables.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideTable;
            private int mDocTraversalDepth;
            private /*final*/ StringBuilder mVisitedTables;
        }
      • visitCommentEnd

        public int visitCommentEnd(Comment comment)
                           throws java.lang.Exception
        Called when enumeration of a comment text has ended.
        Parameters:
        comment - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every comment and comment range in a document.
        public void commentsToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            CommentStructurePrinter visitor = new CommentStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered Comment/CommentRange nodes and their children.
        /// </summary>
        public static class CommentStructurePrinter extends DocumentVisitor {
            public CommentStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideComment = false;
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// A Run is only recorded if it is a child of a Comment or CommentRange node.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideComment) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a CommentRangeStart node is encountered in the document.
            /// </summary>
            public int visitCommentRangeStart(final CommentRangeStart commentRangeStart) {
                indentAndAppendLine("[Comment range start] ID: " + commentRangeStart.getId());
                mDocTraversalDepth++;
                mVisitorIsInsideComment = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a CommentRangeEnd node is encountered in the document.
            /// </summary>
            public int visitCommentRangeEnd(final CommentRangeEnd commentRangeEnd) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Comment range end]");
                mVisitorIsInsideComment = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Comment node is encountered in the document.
            /// </summary>
            public int visitCommentStart(final Comment comment) {
                indentAndAppendLine(MessageFormat.format("[Comment start] For comment range ID {0}, By {1} on {2}", comment.getId(),
                        comment.getAuthor(), comment.getDateTime()));
                mDocTraversalDepth++;
                mVisitorIsInsideComment = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Comment node have been visited.
            /// </summary>
            public int visitCommentEnd(final Comment comment) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Comment end]");
                mVisitorIsInsideComment = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder, and indent it depending on how deep the visitor is
            /// into a comment/comment range's tree of child nodes.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideComment;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitCommentRangeEnd

        public int visitCommentRangeEnd(CommentRangeEnd commentRangeEnd)
                                throws java.lang.Exception
        Called when the end of a commented range of text is encountered.
        Parameters:
        commentRangeEnd - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every comment and comment range in a document.
        public void commentsToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            CommentStructurePrinter visitor = new CommentStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered Comment/CommentRange nodes and their children.
        /// </summary>
        public static class CommentStructurePrinter extends DocumentVisitor {
            public CommentStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideComment = false;
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// A Run is only recorded if it is a child of a Comment or CommentRange node.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideComment) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a CommentRangeStart node is encountered in the document.
            /// </summary>
            public int visitCommentRangeStart(final CommentRangeStart commentRangeStart) {
                indentAndAppendLine("[Comment range start] ID: " + commentRangeStart.getId());
                mDocTraversalDepth++;
                mVisitorIsInsideComment = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a CommentRangeEnd node is encountered in the document.
            /// </summary>
            public int visitCommentRangeEnd(final CommentRangeEnd commentRangeEnd) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Comment range end]");
                mVisitorIsInsideComment = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Comment node is encountered in the document.
            /// </summary>
            public int visitCommentStart(final Comment comment) {
                indentAndAppendLine(MessageFormat.format("[Comment start] For comment range ID {0}, By {1} on {2}", comment.getId(),
                        comment.getAuthor(), comment.getDateTime()));
                mDocTraversalDepth++;
                mVisitorIsInsideComment = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Comment node have been visited.
            /// </summary>
            public int visitCommentEnd(final Comment comment) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Comment end]");
                mVisitorIsInsideComment = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder, and indent it depending on how deep the visitor is
            /// into a comment/comment range's tree of child nodes.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideComment;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitCommentRangeStart

        public int visitCommentRangeStart(CommentRangeStart commentRangeStart)
                                  throws java.lang.Exception
        Called when the start of a commented range of text is encountered.
        Parameters:
        commentRangeStart - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every comment and comment range in a document.
        public void commentsToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            CommentStructurePrinter visitor = new CommentStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered Comment/CommentRange nodes and their children.
        /// </summary>
        public static class CommentStructurePrinter extends DocumentVisitor {
            public CommentStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideComment = false;
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// A Run is only recorded if it is a child of a Comment or CommentRange node.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideComment) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a CommentRangeStart node is encountered in the document.
            /// </summary>
            public int visitCommentRangeStart(final CommentRangeStart commentRangeStart) {
                indentAndAppendLine("[Comment range start] ID: " + commentRangeStart.getId());
                mDocTraversalDepth++;
                mVisitorIsInsideComment = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a CommentRangeEnd node is encountered in the document.
            /// </summary>
            public int visitCommentRangeEnd(final CommentRangeEnd commentRangeEnd) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Comment range end]");
                mVisitorIsInsideComment = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Comment node is encountered in the document.
            /// </summary>
            public int visitCommentStart(final Comment comment) {
                indentAndAppendLine(MessageFormat.format("[Comment start] For comment range ID {0}, By {1} on {2}", comment.getId(),
                        comment.getAuthor(), comment.getDateTime()));
                mDocTraversalDepth++;
                mVisitorIsInsideComment = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Comment node have been visited.
            /// </summary>
            public int visitCommentEnd(final Comment comment) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Comment end]");
                mVisitorIsInsideComment = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder, and indent it depending on how deep the visitor is
            /// into a comment/comment range's tree of child nodes.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideComment;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitCommentStart

        public int visitCommentStart(Comment comment)
                             throws java.lang.Exception
        Called when enumeration of a comment text has started.
        Parameters:
        comment - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Implements the Visitor Pattern to remove all content formatted as hidden from the document.
        public void removeHiddenContentFromDocument() throws Exception {
            // Open the document we want to remove hidden content from
            Document doc = new Document(getMyDir() + "Hidden content.docx");
        
            // Create an object that inherits from the DocumentVisitor class
            RemoveHiddenContentVisitor hiddenContentRemover = new RemoveHiddenContentVisitor();
        
            // This is the well known Visitor pattern. Get the model to accept a visitor
            // The model will iterate through itself by calling the corresponding methods
            // on the visitor object (this is called visiting)
        
            // We can run it over the entire the document like so
            doc.accept(hiddenContentRemover);
        
            // Or we can run it on only a specific node
            Paragraph para = (Paragraph) doc.getChild(NodeType.PARAGRAPH, 4, true);
            para.accept(hiddenContentRemover);
        
            // Or over a different type of node like below
            Table table = (Table) doc.getChild(NodeType.TABLE, 0, true);
            table.accept(hiddenContentRemover);
        
            doc.save(getArtifactsDir() + "Font.RemoveHiddenContentFromDocument.docx");
        }
        
        /**
         * This class when executed will remove all hidden content from the Document. Implemented as a Visitor.
         */
        private class RemoveHiddenContentVisitor extends DocumentVisitor {
            /**
             * Called when a FieldStart node is encountered in the document.
             */
            public int visitFieldStart(final FieldStart fieldStart) throws Exception {
                // If this node is hidden, then remove it
                if (fieldStart.getFont().getHidden()) {
                    fieldStart.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldEnd node is encountered in the document.
             */
            public int visitFieldEnd(final FieldEnd fieldEnd) throws Exception {
                if (fieldEnd.getFont().getHidden()) {
                    fieldEnd.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldSeparator node is encountered in the document.
             */
            public int visitFieldSeparator(final FieldSeparator fieldSeparator) throws Exception {
                if (fieldSeparator.getFont().getHidden()) {
                    fieldSeparator.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Run node is encountered in the document.
             */
            public int visitRun(final Run run) throws Exception {
                if (run.getFont().getHidden()) {
                    run.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Paragraph node is encountered in the document.
             */
            public int visitParagraphStart(final Paragraph paragraph) throws Exception {
                if (paragraph.getParagraphBreakFont().getHidden()) {
                    paragraph.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FormField is encountered in the document.
             */
            public int visitFormField(final FormField field) throws Exception {
                if (field.getFont().getHidden()) {
                    field.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a GroupShape is encountered in the document.
             */
            public int visitGroupShapeStart(final GroupShape groupShape) throws Exception {
                if (groupShape.getFont().getHidden()) {
                    groupShape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Shape is encountered in the document.
             */
            public int visitShapeStart(final Shape shape) throws Exception {
                if (shape.getFont().getHidden()) {
                    shape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Comment is encountered in the document.
             */
            public int visitCommentStart(final Comment comment) throws Exception {
                if (comment.getFont().getHidden()) {
                    comment.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Footnote is encountered in the document.
             */
            public int visitFootnoteStart(final Footnote footnote) throws Exception {
                if (footnote.getFont().getHidden()) {
                    footnote.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SpecialCharacter is encountered in the document.
            /// </summary>
            public /*override*/ /*VisitorAction*/int visitSpecialChar(SpecialChar specialChar) {
                if (specialChar.getFont().getHidden())
                    specialChar.remove();
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Table node is ended in the document.
             */
            public int visitTableEnd(final Table table) {
                // At the moment there is no way to tell if a particular Table/Row/Cell is hidden.
                // Instead, if the content of a table is hidden, then all inline child nodes of the table should be
                // hidden and thus removed by previous visits as well. This will result in the container being empty
                // so if this is the case we know to remove the table node.
                //
                // Note that a table which is not hidden but simply has no content will not be affected by this algorithm,
                // as technically they are not completely empty (for example a properly formed Cell will have at least 
                // an empty paragraph in it)
                if (!table.hasChildNodes()) {
                    table.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Cell node is ended in the document.
             */
            public int visitCellEnd(final Cell cell) {
                if (!cell.hasChildNodes() && cell.getParentNode() != null) {
                    cell.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Row node is ended in the document.
             */
            public int visitRowEnd(final Row row) {
                if (!row.hasChildNodes() && row.getParentNode() != null) {
                    row.remove();
                }
        
                return VisitorAction.CONTINUE;
            }

        Example:

        Shows how to print the node structure of every comment and comment range in a document.
        public void commentsToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            CommentStructurePrinter visitor = new CommentStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered Comment/CommentRange nodes and their children.
        /// </summary>
        public static class CommentStructurePrinter extends DocumentVisitor {
            public CommentStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideComment = false;
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// A Run is only recorded if it is a child of a Comment or CommentRange node.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideComment) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a CommentRangeStart node is encountered in the document.
            /// </summary>
            public int visitCommentRangeStart(final CommentRangeStart commentRangeStart) {
                indentAndAppendLine("[Comment range start] ID: " + commentRangeStart.getId());
                mDocTraversalDepth++;
                mVisitorIsInsideComment = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a CommentRangeEnd node is encountered in the document.
            /// </summary>
            public int visitCommentRangeEnd(final CommentRangeEnd commentRangeEnd) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Comment range end]");
                mVisitorIsInsideComment = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Comment node is encountered in the document.
            /// </summary>
            public int visitCommentStart(final Comment comment) {
                indentAndAppendLine(MessageFormat.format("[Comment start] For comment range ID {0}, By {1} on {2}", comment.getId(),
                        comment.getAuthor(), comment.getDateTime()));
                mDocTraversalDepth++;
                mVisitorIsInsideComment = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Comment node have been visited.
            /// </summary>
            public int visitCommentEnd(final Comment comment) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Comment end]");
                mVisitorIsInsideComment = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder, and indent it depending on how deep the visitor is
            /// into a comment/comment range's tree of child nodes.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideComment;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitDocumentEnd

        public int visitDocumentEnd(Document doc)
                            throws java.lang.Exception
        Called when enumeration of the document has finished.
        Parameters:
        doc - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to use a document visitor to print a document's node structure.
        public void docStructureToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            DocStructurePrinter visitor = new DocStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's tree of child nodes, and creates a map of this tree in the form of a string.
        /// </summary>
        public static class DocStructurePrinter extends DocumentVisitor {
            public DocStructurePrinter() {
                mAcceptingNodeChildTree = new StringBuilder();
            }
        
            public String getText() {
                return mAcceptingNodeChildTree.toString();
            }
        
            /// <summary>
            /// Called when a Document node is encountered.
            /// </summary>
            public int visitDocumentStart(Document doc) {
                int childNodeCount = doc.getChildNodes(NodeType.ANY, true).getCount();
        
                indentAndAppendLine("[Document start] Child nodes: " + childNodeCount);
                mDocTraversalDepth++;
        
                // Allow the visitor to continue visiting other nodes.
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Document node have been visited.
            /// </summary>
            public int visitDocumentEnd(Document doc) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Document end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Section node is encountered in the document.
            /// </summary>
            public int visitSectionStart(final Section section) {
                // Get the index of our section within the document
                NodeCollection docSections = section.getDocument().getChildNodes(NodeType.SECTION, false);
                int sectionIndex = docSections.indexOf(section);
        
                indentAndAppendLine("[Section start] Section index: " + sectionIndex);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Section node have been visited.
            /// </summary>
            public int visitSectionEnd(final Section section) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Section end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Body node is encountered in the document.
            /// </summary>
            public int visitBodyStart(final Body body) {
                int paragraphCount = body.getParagraphs().getCount();
                indentAndAppendLine("[Body start] Paragraphs: " + paragraphCount);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Body node have been visited.
            /// </summary>
            public int visitBodyEnd(final Body body) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Body end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Paragraph node is encountered in the document.
            /// </summary>
            public int visitParagraphStart(final Paragraph paragraph) {
                indentAndAppendLine("[Paragraph start]");
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Paragraph node have been visited.
            /// </summary>
            public int visitParagraphEnd(final Paragraph paragraph) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Paragraph end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SubDocument node is encountered in the document.
            /// </summary>
            public int visitSubDocument(final SubDocument subDocument) {
                indentAndAppendLine("[SubDocument]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mAcceptingNodeChildTree.append("|  ");
                }
        
                mAcceptingNodeChildTree.append(text + "\r\n");
            }
        
            private int mDocTraversalDepth;
            private StringBuilder mAcceptingNodeChildTree;
        }
      • visitDocumentStart

        public int visitDocumentStart(Document doc)
                              throws java.lang.Exception
        Called when enumeration of the document has started.
        Parameters:
        doc - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to use a document visitor to print a document's node structure.
        public void docStructureToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            DocStructurePrinter visitor = new DocStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's tree of child nodes, and creates a map of this tree in the form of a string.
        /// </summary>
        public static class DocStructurePrinter extends DocumentVisitor {
            public DocStructurePrinter() {
                mAcceptingNodeChildTree = new StringBuilder();
            }
        
            public String getText() {
                return mAcceptingNodeChildTree.toString();
            }
        
            /// <summary>
            /// Called when a Document node is encountered.
            /// </summary>
            public int visitDocumentStart(Document doc) {
                int childNodeCount = doc.getChildNodes(NodeType.ANY, true).getCount();
        
                indentAndAppendLine("[Document start] Child nodes: " + childNodeCount);
                mDocTraversalDepth++;
        
                // Allow the visitor to continue visiting other nodes.
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Document node have been visited.
            /// </summary>
            public int visitDocumentEnd(Document doc) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Document end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Section node is encountered in the document.
            /// </summary>
            public int visitSectionStart(final Section section) {
                // Get the index of our section within the document
                NodeCollection docSections = section.getDocument().getChildNodes(NodeType.SECTION, false);
                int sectionIndex = docSections.indexOf(section);
        
                indentAndAppendLine("[Section start] Section index: " + sectionIndex);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Section node have been visited.
            /// </summary>
            public int visitSectionEnd(final Section section) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Section end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Body node is encountered in the document.
            /// </summary>
            public int visitBodyStart(final Body body) {
                int paragraphCount = body.getParagraphs().getCount();
                indentAndAppendLine("[Body start] Paragraphs: " + paragraphCount);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Body node have been visited.
            /// </summary>
            public int visitBodyEnd(final Body body) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Body end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Paragraph node is encountered in the document.
            /// </summary>
            public int visitParagraphStart(final Paragraph paragraph) {
                indentAndAppendLine("[Paragraph start]");
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Paragraph node have been visited.
            /// </summary>
            public int visitParagraphEnd(final Paragraph paragraph) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Paragraph end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SubDocument node is encountered in the document.
            /// </summary>
            public int visitSubDocument(final SubDocument subDocument) {
                indentAndAppendLine("[SubDocument]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mAcceptingNodeChildTree.append("|  ");
                }
        
                mAcceptingNodeChildTree.append(text + "\r\n");
            }
        
            private int mDocTraversalDepth;
            private StringBuilder mAcceptingNodeChildTree;
        }
      • visitEditableRangeEnd

        public int visitEditableRangeEnd(EditableRangeEnd editableRangeEnd)
                                 throws java.lang.Exception
        Called when an end of an editable range is encountered in the document.
        Parameters:
        editableRangeEnd - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every editable range in a document.
        public void editableRangeToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            EditableRangeStructurePrinter visitor = new EditableRangeStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered EditableRange nodes and their children.
        /// </summary>
        public static class EditableRangeStructurePrinter extends DocumentVisitor {
            public EditableRangeStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideEditableRange = false;
            }
        
            /// <summary>
            /// Gets the plain text of the document that was accumulated by the visitor.
            /// </summary>
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                // We want to print the contents of runs, but only if they are inside shapes, as they would be in the case of text boxes
                if (mVisitorIsInsideEditableRange) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when an EditableRange node is encountered in the document.
            /// </summary>
            public int visitEditableRangeStart(final EditableRangeStart editableRangeStart) {
                indentAndAppendLine("[EditableRange start] ID: " + editableRangeStart.getId() + " Owner: "
                        + editableRangeStart.getEditableRange().getSingleUser());
                mDocTraversalDepth++;
                mVisitorIsInsideEditableRange = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when the visiting of a EditableRange node is ended.
            /// </summary>
            public int visitEditableRangeEnd(final EditableRangeEnd editableRangeEnd) {
                mDocTraversalDepth--;
                indentAndAppendLine("[EditableRange end]");
                mVisitorIsInsideEditableRange = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideEditableRange;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitEditableRangeStart

        public int visitEditableRangeStart(EditableRangeStart editableRangeStart)
                                   throws java.lang.Exception
        Called when a start of an editable range is encountered in the document.
        Parameters:
        editableRangeStart - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every editable range in a document.
        public void editableRangeToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            EditableRangeStructurePrinter visitor = new EditableRangeStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered EditableRange nodes and their children.
        /// </summary>
        public static class EditableRangeStructurePrinter extends DocumentVisitor {
            public EditableRangeStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideEditableRange = false;
            }
        
            /// <summary>
            /// Gets the plain text of the document that was accumulated by the visitor.
            /// </summary>
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                // We want to print the contents of runs, but only if they are inside shapes, as they would be in the case of text boxes
                if (mVisitorIsInsideEditableRange) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when an EditableRange node is encountered in the document.
            /// </summary>
            public int visitEditableRangeStart(final EditableRangeStart editableRangeStart) {
                indentAndAppendLine("[EditableRange start] ID: " + editableRangeStart.getId() + " Owner: "
                        + editableRangeStart.getEditableRange().getSingleUser());
                mDocTraversalDepth++;
                mVisitorIsInsideEditableRange = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when the visiting of a EditableRange node is ended.
            /// </summary>
            public int visitEditableRangeEnd(final EditableRangeEnd editableRangeEnd) {
                mDocTraversalDepth--;
                indentAndAppendLine("[EditableRange end]");
                mVisitorIsInsideEditableRange = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideEditableRange;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitFieldEnd

        public int visitFieldEnd(FieldEnd fieldEnd)
                         throws java.lang.Exception
        Called when a field ends in the document.

        For more info see visitFieldStart(com.aspose.words.FieldStart)

        Parameters:
        fieldEnd - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every field in a document.
        public void fieldToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            FieldStructurePrinter visitor = new FieldStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered Field nodes and their children.
        /// </summary>
        public static class FieldStructurePrinter extends DocumentVisitor {
            public FieldStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideField = false;
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideField) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a FieldStart node is encountered in the document.
            /// </summary>
            public int visitFieldStart(final FieldStart fieldStart) {
                indentAndAppendLine("[Field start] FieldType: " + fieldStart.getFieldType());
                mDocTraversalDepth++;
                mVisitorIsInsideField = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a FieldEnd node is encountered in the document.
            /// </summary>
            public int visitFieldEnd(final FieldEnd fieldEnd) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Field end]");
                mVisitorIsInsideField = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a FieldSeparator node is encountered in the document.
            /// </summary>
            public int visitFieldSeparator(final FieldSeparator fieldSeparator) {
                indentAndAppendLine("[FieldSeparator]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder, and indent it depending on how deep the visitor is
            /// into the field's tree of child nodes.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideField;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitFieldSeparator

        public int visitFieldSeparator(FieldSeparator fieldSeparator)
                               throws java.lang.Exception
        Called when a field separator is encountered in the document.

        The field separator separates field code from field value in the document. Note that some fields have only field code and do not have field separator and field value.

        For more info see visitFieldStart(com.aspose.words.FieldStart)

        Parameters:
        fieldSeparator - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every field in a document.
        public void fieldToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            FieldStructurePrinter visitor = new FieldStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered Field nodes and their children.
        /// </summary>
        public static class FieldStructurePrinter extends DocumentVisitor {
            public FieldStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideField = false;
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideField) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a FieldStart node is encountered in the document.
            /// </summary>
            public int visitFieldStart(final FieldStart fieldStart) {
                indentAndAppendLine("[Field start] FieldType: " + fieldStart.getFieldType());
                mDocTraversalDepth++;
                mVisitorIsInsideField = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a FieldEnd node is encountered in the document.
            /// </summary>
            public int visitFieldEnd(final FieldEnd fieldEnd) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Field end]");
                mVisitorIsInsideField = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a FieldSeparator node is encountered in the document.
            /// </summary>
            public int visitFieldSeparator(final FieldSeparator fieldSeparator) {
                indentAndAppendLine("[FieldSeparator]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder, and indent it depending on how deep the visitor is
            /// into the field's tree of child nodes.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideField;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitFieldStart

        public int visitFieldStart(FieldStart fieldStart)
                           throws java.lang.Exception
        Called when a field starts in the document.

        A field in a Word Word document consists of a field code and field value.

        For example, a field that displays a page number can be represented as follows:

        [FieldStart]PAGE[FieldSeparator]98[FieldEnd]

        The field separator separates field code from field value in the document. Note that some fields have only field code and do not have field separator and field value.

        Fields can be nested.

        Parameters:
        fieldStart - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every field in a document.
        public void fieldToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            FieldStructurePrinter visitor = new FieldStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered Field nodes and their children.
        /// </summary>
        public static class FieldStructurePrinter extends DocumentVisitor {
            public FieldStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideField = false;
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideField) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a FieldStart node is encountered in the document.
            /// </summary>
            public int visitFieldStart(final FieldStart fieldStart) {
                indentAndAppendLine("[Field start] FieldType: " + fieldStart.getFieldType());
                mDocTraversalDepth++;
                mVisitorIsInsideField = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a FieldEnd node is encountered in the document.
            /// </summary>
            public int visitFieldEnd(final FieldEnd fieldEnd) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Field end]");
                mVisitorIsInsideField = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a FieldSeparator node is encountered in the document.
            /// </summary>
            public int visitFieldSeparator(final FieldSeparator fieldSeparator) {
                indentAndAppendLine("[FieldSeparator]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder, and indent it depending on how deep the visitor is
            /// into the field's tree of child nodes.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideField;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitFootnoteEnd

        public int visitFootnoteEnd(Footnote footnote)
                            throws java.lang.Exception
        Called when enumeration of a footnote or endnote text has ended.
        Parameters:
        footnote - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every footnote in a document.
        public void footnoteToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            FootnoteStructurePrinter visitor = new FootnoteStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered Footnote nodes and their children.
        /// </summary>
        public static class FootnoteStructurePrinter extends DocumentVisitor {
            public FootnoteStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideFootnote = false;
            }
        
            /// <summary>
            /// Gets the plain text of the document that was accumulated by the visitor.
            /// </summary>
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Footnote node is encountered in the document.
            /// </summary>
            public int visitFootnoteStart(final Footnote footnote) {
                indentAndAppendLine("[Footnote start] Type: " + footnote.getFootnoteType());
                mDocTraversalDepth++;
                mVisitorIsInsideFootnote = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Footnote node have been visited.
            /// </summary>
            public int visitFootnoteEnd(final Footnote footnote) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Footnote end]");
                mVisitorIsInsideFootnote = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideFootnote) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideFootnote;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitFootnoteStart

        public int visitFootnoteStart(Footnote footnote)
                              throws java.lang.Exception
        Called when enumeration of a footnote or endnote text has started.
        Parameters:
        footnote - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Implements the Visitor Pattern to remove all content formatted as hidden from the document.
        public void removeHiddenContentFromDocument() throws Exception {
            // Open the document we want to remove hidden content from
            Document doc = new Document(getMyDir() + "Hidden content.docx");
        
            // Create an object that inherits from the DocumentVisitor class
            RemoveHiddenContentVisitor hiddenContentRemover = new RemoveHiddenContentVisitor();
        
            // This is the well known Visitor pattern. Get the model to accept a visitor
            // The model will iterate through itself by calling the corresponding methods
            // on the visitor object (this is called visiting)
        
            // We can run it over the entire the document like so
            doc.accept(hiddenContentRemover);
        
            // Or we can run it on only a specific node
            Paragraph para = (Paragraph) doc.getChild(NodeType.PARAGRAPH, 4, true);
            para.accept(hiddenContentRemover);
        
            // Or over a different type of node like below
            Table table = (Table) doc.getChild(NodeType.TABLE, 0, true);
            table.accept(hiddenContentRemover);
        
            doc.save(getArtifactsDir() + "Font.RemoveHiddenContentFromDocument.docx");
        }
        
        /**
         * This class when executed will remove all hidden content from the Document. Implemented as a Visitor.
         */
        private class RemoveHiddenContentVisitor extends DocumentVisitor {
            /**
             * Called when a FieldStart node is encountered in the document.
             */
            public int visitFieldStart(final FieldStart fieldStart) throws Exception {
                // If this node is hidden, then remove it
                if (fieldStart.getFont().getHidden()) {
                    fieldStart.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldEnd node is encountered in the document.
             */
            public int visitFieldEnd(final FieldEnd fieldEnd) throws Exception {
                if (fieldEnd.getFont().getHidden()) {
                    fieldEnd.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldSeparator node is encountered in the document.
             */
            public int visitFieldSeparator(final FieldSeparator fieldSeparator) throws Exception {
                if (fieldSeparator.getFont().getHidden()) {
                    fieldSeparator.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Run node is encountered in the document.
             */
            public int visitRun(final Run run) throws Exception {
                if (run.getFont().getHidden()) {
                    run.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Paragraph node is encountered in the document.
             */
            public int visitParagraphStart(final Paragraph paragraph) throws Exception {
                if (paragraph.getParagraphBreakFont().getHidden()) {
                    paragraph.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FormField is encountered in the document.
             */
            public int visitFormField(final FormField field) throws Exception {
                if (field.getFont().getHidden()) {
                    field.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a GroupShape is encountered in the document.
             */
            public int visitGroupShapeStart(final GroupShape groupShape) throws Exception {
                if (groupShape.getFont().getHidden()) {
                    groupShape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Shape is encountered in the document.
             */
            public int visitShapeStart(final Shape shape) throws Exception {
                if (shape.getFont().getHidden()) {
                    shape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Comment is encountered in the document.
             */
            public int visitCommentStart(final Comment comment) throws Exception {
                if (comment.getFont().getHidden()) {
                    comment.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Footnote is encountered in the document.
             */
            public int visitFootnoteStart(final Footnote footnote) throws Exception {
                if (footnote.getFont().getHidden()) {
                    footnote.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SpecialCharacter is encountered in the document.
            /// </summary>
            public /*override*/ /*VisitorAction*/int visitSpecialChar(SpecialChar specialChar) {
                if (specialChar.getFont().getHidden())
                    specialChar.remove();
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Table node is ended in the document.
             */
            public int visitTableEnd(final Table table) {
                // At the moment there is no way to tell if a particular Table/Row/Cell is hidden.
                // Instead, if the content of a table is hidden, then all inline child nodes of the table should be
                // hidden and thus removed by previous visits as well. This will result in the container being empty
                // so if this is the case we know to remove the table node.
                //
                // Note that a table which is not hidden but simply has no content will not be affected by this algorithm,
                // as technically they are not completely empty (for example a properly formed Cell will have at least 
                // an empty paragraph in it)
                if (!table.hasChildNodes()) {
                    table.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Cell node is ended in the document.
             */
            public int visitCellEnd(final Cell cell) {
                if (!cell.hasChildNodes() && cell.getParentNode() != null) {
                    cell.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Row node is ended in the document.
             */
            public int visitRowEnd(final Row row) {
                if (!row.hasChildNodes() && row.getParentNode() != null) {
                    row.remove();
                }
        
                return VisitorAction.CONTINUE;
            }

        Example:

        Shows how to print the node structure of every footnote in a document.
        public void footnoteToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            FootnoteStructurePrinter visitor = new FootnoteStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered Footnote nodes and their children.
        /// </summary>
        public static class FootnoteStructurePrinter extends DocumentVisitor {
            public FootnoteStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideFootnote = false;
            }
        
            /// <summary>
            /// Gets the plain text of the document that was accumulated by the visitor.
            /// </summary>
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Footnote node is encountered in the document.
            /// </summary>
            public int visitFootnoteStart(final Footnote footnote) {
                indentAndAppendLine("[Footnote start] Type: " + footnote.getFootnoteType());
                mDocTraversalDepth++;
                mVisitorIsInsideFootnote = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Footnote node have been visited.
            /// </summary>
            public int visitFootnoteEnd(final Footnote footnote) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Footnote end]");
                mVisitorIsInsideFootnote = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideFootnote) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideFootnote;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitFormField

        public int visitFormField(FormField formField)
                          throws java.lang.Exception
        Called when a form field is encountered in the document.
        Parameters:
        formField - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Implements the Visitor Pattern to remove all content formatted as hidden from the document.
        public void removeHiddenContentFromDocument() throws Exception {
            // Open the document we want to remove hidden content from
            Document doc = new Document(getMyDir() + "Hidden content.docx");
        
            // Create an object that inherits from the DocumentVisitor class
            RemoveHiddenContentVisitor hiddenContentRemover = new RemoveHiddenContentVisitor();
        
            // This is the well known Visitor pattern. Get the model to accept a visitor
            // The model will iterate through itself by calling the corresponding methods
            // on the visitor object (this is called visiting)
        
            // We can run it over the entire the document like so
            doc.accept(hiddenContentRemover);
        
            // Or we can run it on only a specific node
            Paragraph para = (Paragraph) doc.getChild(NodeType.PARAGRAPH, 4, true);
            para.accept(hiddenContentRemover);
        
            // Or over a different type of node like below
            Table table = (Table) doc.getChild(NodeType.TABLE, 0, true);
            table.accept(hiddenContentRemover);
        
            doc.save(getArtifactsDir() + "Font.RemoveHiddenContentFromDocument.docx");
        }
        
        /**
         * This class when executed will remove all hidden content from the Document. Implemented as a Visitor.
         */
        private class RemoveHiddenContentVisitor extends DocumentVisitor {
            /**
             * Called when a FieldStart node is encountered in the document.
             */
            public int visitFieldStart(final FieldStart fieldStart) throws Exception {
                // If this node is hidden, then remove it
                if (fieldStart.getFont().getHidden()) {
                    fieldStart.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldEnd node is encountered in the document.
             */
            public int visitFieldEnd(final FieldEnd fieldEnd) throws Exception {
                if (fieldEnd.getFont().getHidden()) {
                    fieldEnd.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldSeparator node is encountered in the document.
             */
            public int visitFieldSeparator(final FieldSeparator fieldSeparator) throws Exception {
                if (fieldSeparator.getFont().getHidden()) {
                    fieldSeparator.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Run node is encountered in the document.
             */
            public int visitRun(final Run run) throws Exception {
                if (run.getFont().getHidden()) {
                    run.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Paragraph node is encountered in the document.
             */
            public int visitParagraphStart(final Paragraph paragraph) throws Exception {
                if (paragraph.getParagraphBreakFont().getHidden()) {
                    paragraph.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FormField is encountered in the document.
             */
            public int visitFormField(final FormField field) throws Exception {
                if (field.getFont().getHidden()) {
                    field.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a GroupShape is encountered in the document.
             */
            public int visitGroupShapeStart(final GroupShape groupShape) throws Exception {
                if (groupShape.getFont().getHidden()) {
                    groupShape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Shape is encountered in the document.
             */
            public int visitShapeStart(final Shape shape) throws Exception {
                if (shape.getFont().getHidden()) {
                    shape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Comment is encountered in the document.
             */
            public int visitCommentStart(final Comment comment) throws Exception {
                if (comment.getFont().getHidden()) {
                    comment.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Footnote is encountered in the document.
             */
            public int visitFootnoteStart(final Footnote footnote) throws Exception {
                if (footnote.getFont().getHidden()) {
                    footnote.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SpecialCharacter is encountered in the document.
            /// </summary>
            public /*override*/ /*VisitorAction*/int visitSpecialChar(SpecialChar specialChar) {
                if (specialChar.getFont().getHidden())
                    specialChar.remove();
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Table node is ended in the document.
             */
            public int visitTableEnd(final Table table) {
                // At the moment there is no way to tell if a particular Table/Row/Cell is hidden.
                // Instead, if the content of a table is hidden, then all inline child nodes of the table should be
                // hidden and thus removed by previous visits as well. This will result in the container being empty
                // so if this is the case we know to remove the table node.
                //
                // Note that a table which is not hidden but simply has no content will not be affected by this algorithm,
                // as technically they are not completely empty (for example a properly formed Cell will have at least 
                // an empty paragraph in it)
                if (!table.hasChildNodes()) {
                    table.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Cell node is ended in the document.
             */
            public int visitCellEnd(final Cell cell) {
                if (!cell.hasChildNodes() && cell.getParentNode() != null) {
                    cell.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Row node is ended in the document.
             */
            public int visitRowEnd(final Row row) {
                if (!row.hasChildNodes() && row.getParentNode() != null) {
                    row.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
      • visitGlossaryDocumentEnd

        public int visitGlossaryDocumentEnd(GlossaryDocument glossary)
                                    throws java.lang.Exception
        Called when enumeration of a glossary document has ended.

        Note: A glossary document node and its children are not visited when you execute a Visitor over a Document. If you want to execute a Visitor over a glossary document, you need to call GlossaryDocument.accept(com.aspose.words.DocumentVisitor).

        Parameters:
        glossary - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows ways of accessing building blocks in a glossary document.
        public void glossaryDocument() throws Exception {
            Document doc = new Document();
            GlossaryDocument glossaryDoc = new GlossaryDocument();
        
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 1"));
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 2"));
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 3"));
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 4"));
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 5"));
        
            Assert.assertEquals(glossaryDoc.getBuildingBlocks().getCount(), 5);
        
            doc.setGlossaryDocument(glossaryDoc);
        
            // There are various ways of accessing building blocks.
            // 1 -  Get the first/last building blocks in the collection:
            Assert.assertEquals("Block 1", glossaryDoc.getFirstBuildingBlock().getName());
            Assert.assertEquals("Block 5", glossaryDoc.getLastBuildingBlock().getName());
        
            // 2 -  Get a building block by index:
            Assert.assertEquals("Block 2", glossaryDoc.getBuildingBlocks().get(1).getName());
            Assert.assertEquals("Block 3", glossaryDoc.getBuildingBlocks().toArray()[2].getName());
        
            // 3 -  Get the first building block that matches a gallery, name and category:
            Assert.assertEquals("Block 4", 
                glossaryDoc.getBuildingBlock(BuildingBlockGallery.ALL, "(Empty Category)", "Block 4").getName());
        
            // We will do that using a custom visitor,
            // which will give every BuildingBlock in the GlossaryDocument a unique GUID
            GlossaryDocVisitor visitor = new GlossaryDocVisitor();
            glossaryDoc.accept(visitor);
        
            System.out.println(visitor.getText());
        
            // When we open this document using Microsoft Word,
            // we can find the building blocks via Insert -> Quick Parts -> Building Blocks Organizer.
            doc.save(getArtifactsDir() + "BuildingBlocks.GlossaryDocument.dotx"); 
        }
        
        public static BuildingBlock createNewBuildingBlock(final GlossaryDocument glossaryDoc, final String buildingBlockName) {
            BuildingBlock buildingBlock = new BuildingBlock(glossaryDoc);
            buildingBlock.setName(buildingBlockName);
        
            return buildingBlock;
        }
        
        /// <summary>
        /// Gives each building block in a visited glossary document a unique GUID, and stores the GUID-building block pairs in a dictionary.
        /// </summary>
        public static class GlossaryDocVisitor extends DocumentVisitor {
            public GlossaryDocVisitor() {
                mBlocksByGuid = new HashMap<>();
                mBuilder = new StringBuilder();
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            public HashMap<UUID, BuildingBlock> getDictionary() {
                return mBlocksByGuid;
            }
        
            public int visitGlossaryDocumentStart(final GlossaryDocument glossary) {
                mBuilder.append("Glossary document found!\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitGlossaryDocumentEnd(final GlossaryDocument glossary) {
                mBuilder.append("Reached end of glossary!\n");
                mBuilder.append("BuildingBlocks found: " + mBlocksByGuid.size() + "\r\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitBuildingBlockStart(final BuildingBlock block) {
                block.setGuid(UUID.randomUUID());
                mBlocksByGuid.put(block.getGuid(), block);
                return VisitorAction.CONTINUE;
            }
        
            public int visitBuildingBlockEnd(final BuildingBlock block) {
                mBuilder.append("\tVisited block \"" + block.getName() + "\"" + "\r\n");
                mBuilder.append("\t Type: " + block.getType() + "\r\n");
                mBuilder.append("\t Gallery: " + block.getGallery() + "\r\n");
                mBuilder.append("\t Behavior: " + block.getBehavior() + "\r\n");
                mBuilder.append("\t Description: " + block.getDescription() + "\r\n");
        
                return VisitorAction.CONTINUE;
            }
        
            private HashMap<UUID, BuildingBlock> mBlocksByGuid;
            private StringBuilder mBuilder;
        }
      • visitGlossaryDocumentStart

        public int visitGlossaryDocumentStart(GlossaryDocument glossary)
                                      throws java.lang.Exception
        Called when enumeration of a glossary document has started.

        Note: A glossary document node and its children are not visited when you execute a Visitor over a Document. If you want to execute a Visitor over a glossary document, you need to call GlossaryDocument.accept(com.aspose.words.DocumentVisitor).

        Parameters:
        glossary - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows ways of accessing building blocks in a glossary document.
        public void glossaryDocument() throws Exception {
            Document doc = new Document();
            GlossaryDocument glossaryDoc = new GlossaryDocument();
        
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 1"));
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 2"));
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 3"));
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 4"));
            glossaryDoc.appendChild(createNewBuildingBlock(glossaryDoc, "Block 5"));
        
            Assert.assertEquals(glossaryDoc.getBuildingBlocks().getCount(), 5);
        
            doc.setGlossaryDocument(glossaryDoc);
        
            // There are various ways of accessing building blocks.
            // 1 -  Get the first/last building blocks in the collection:
            Assert.assertEquals("Block 1", glossaryDoc.getFirstBuildingBlock().getName());
            Assert.assertEquals("Block 5", glossaryDoc.getLastBuildingBlock().getName());
        
            // 2 -  Get a building block by index:
            Assert.assertEquals("Block 2", glossaryDoc.getBuildingBlocks().get(1).getName());
            Assert.assertEquals("Block 3", glossaryDoc.getBuildingBlocks().toArray()[2].getName());
        
            // 3 -  Get the first building block that matches a gallery, name and category:
            Assert.assertEquals("Block 4", 
                glossaryDoc.getBuildingBlock(BuildingBlockGallery.ALL, "(Empty Category)", "Block 4").getName());
        
            // We will do that using a custom visitor,
            // which will give every BuildingBlock in the GlossaryDocument a unique GUID
            GlossaryDocVisitor visitor = new GlossaryDocVisitor();
            glossaryDoc.accept(visitor);
        
            System.out.println(visitor.getText());
        
            // When we open this document using Microsoft Word,
            // we can find the building blocks via Insert -> Quick Parts -> Building Blocks Organizer.
            doc.save(getArtifactsDir() + "BuildingBlocks.GlossaryDocument.dotx"); 
        }
        
        public static BuildingBlock createNewBuildingBlock(final GlossaryDocument glossaryDoc, final String buildingBlockName) {
            BuildingBlock buildingBlock = new BuildingBlock(glossaryDoc);
            buildingBlock.setName(buildingBlockName);
        
            return buildingBlock;
        }
        
        /// <summary>
        /// Gives each building block in a visited glossary document a unique GUID, and stores the GUID-building block pairs in a dictionary.
        /// </summary>
        public static class GlossaryDocVisitor extends DocumentVisitor {
            public GlossaryDocVisitor() {
                mBlocksByGuid = new HashMap<>();
                mBuilder = new StringBuilder();
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            public HashMap<UUID, BuildingBlock> getDictionary() {
                return mBlocksByGuid;
            }
        
            public int visitGlossaryDocumentStart(final GlossaryDocument glossary) {
                mBuilder.append("Glossary document found!\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitGlossaryDocumentEnd(final GlossaryDocument glossary) {
                mBuilder.append("Reached end of glossary!\n");
                mBuilder.append("BuildingBlocks found: " + mBlocksByGuid.size() + "\r\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitBuildingBlockStart(final BuildingBlock block) {
                block.setGuid(UUID.randomUUID());
                mBlocksByGuid.put(block.getGuid(), block);
                return VisitorAction.CONTINUE;
            }
        
            public int visitBuildingBlockEnd(final BuildingBlock block) {
                mBuilder.append("\tVisited block \"" + block.getName() + "\"" + "\r\n");
                mBuilder.append("\t Type: " + block.getType() + "\r\n");
                mBuilder.append("\t Gallery: " + block.getGallery() + "\r\n");
                mBuilder.append("\t Behavior: " + block.getBehavior() + "\r\n");
                mBuilder.append("\t Description: " + block.getDescription() + "\r\n");
        
                return VisitorAction.CONTINUE;
            }
        
            private HashMap<UUID, BuildingBlock> mBlocksByGuid;
            private StringBuilder mBuilder;
        }
      • visitGroupShapeEnd

        public int visitGroupShapeEnd(GroupShape groupShape)
                              throws java.lang.Exception
        Called when enumeration of a group shape has ended.
        Parameters:
        groupShape - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to create a group of shapes, and let it accept a visitor
        public void groupOfShapes() throws Exception {
            Document doc = new Document();
            DocumentBuilder builder = new DocumentBuilder(doc);
        
            // If you need to create "NonPrimitive" shapes, like SingleCornerSnipped, TopCornersSnipped, DiagonalCornersSnipped,
            // TopCornersOneRoundedOneSnipped, SingleCornerRounded, TopCornersRounded, DiagonalCornersRounded
            // please use DocumentBuilder.InsertShape methods
            Shape balloon = new Shape(doc, ShapeType.BALLOON);
            balloon.setWidth(200.0);
            balloon.setHeight(200.0);
            balloon.setStrokeColor(Color.RED);
        
            Shape cube = new Shape(doc, ShapeType.CUBE);
            cube.setWidth(100.0);
            cube.setHeight(100.0);
            cube.setStrokeColor(Color.BLUE);
        
            GroupShape group = new GroupShape(doc);
            group.appendChild(balloon);
            group.appendChild(cube);
        
            Assert.assertTrue(group.isGroup());
            builder.insertNode(group);
        
            ShapeInfoPrinter printer = new ShapeInfoPrinter();
            group.accept(printer);
        
            System.out.println(printer.getText());
        }
        
        /// <summary>
        /// Visitor that prints shape group contents information to the console.
        /// </summary>
        public static class ShapeInfoPrinter extends DocumentVisitor {
            public ShapeInfoPrinter() {
                mBuilder = new StringBuilder();
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            public int visitGroupShapeStart(final GroupShape groupShape) {
                mBuilder.append("Shape group started:\r\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitGroupShapeEnd(final GroupShape groupShape) {
                mBuilder.append("End of shape group\r\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitShapeStart(final Shape shape) {
                mBuilder.append("\tShape - " + shape.getShapeType() + ":\r\n");
                mBuilder.append("\t\tWidth: " + shape.getWidth() + "\r\n");
                mBuilder.append("\t\tHeight: " + shape.getHeight() + "\r\n");
                mBuilder.append("\t\tStroke color: " + shape.getStroke().getColor() + "\r\n");
                mBuilder.append("\t\tFill color: " + shape.getFill().getColor() + "\r\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitShapeEnd(final Shape shape) {
                mBuilder.append("\tEnd of shape\r\n");
                return VisitorAction.CONTINUE;
            }
        
            private StringBuilder mBuilder;
        }
      • visitGroupShapeStart

        public int visitGroupShapeStart(GroupShape groupShape)
                                throws java.lang.Exception
        Called when enumeration of a group shape has started.
        Parameters:
        groupShape - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Implements the Visitor Pattern to remove all content formatted as hidden from the document.
        public void removeHiddenContentFromDocument() throws Exception {
            // Open the document we want to remove hidden content from
            Document doc = new Document(getMyDir() + "Hidden content.docx");
        
            // Create an object that inherits from the DocumentVisitor class
            RemoveHiddenContentVisitor hiddenContentRemover = new RemoveHiddenContentVisitor();
        
            // This is the well known Visitor pattern. Get the model to accept a visitor
            // The model will iterate through itself by calling the corresponding methods
            // on the visitor object (this is called visiting)
        
            // We can run it over the entire the document like so
            doc.accept(hiddenContentRemover);
        
            // Or we can run it on only a specific node
            Paragraph para = (Paragraph) doc.getChild(NodeType.PARAGRAPH, 4, true);
            para.accept(hiddenContentRemover);
        
            // Or over a different type of node like below
            Table table = (Table) doc.getChild(NodeType.TABLE, 0, true);
            table.accept(hiddenContentRemover);
        
            doc.save(getArtifactsDir() + "Font.RemoveHiddenContentFromDocument.docx");
        }
        
        /**
         * This class when executed will remove all hidden content from the Document. Implemented as a Visitor.
         */
        private class RemoveHiddenContentVisitor extends DocumentVisitor {
            /**
             * Called when a FieldStart node is encountered in the document.
             */
            public int visitFieldStart(final FieldStart fieldStart) throws Exception {
                // If this node is hidden, then remove it
                if (fieldStart.getFont().getHidden()) {
                    fieldStart.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldEnd node is encountered in the document.
             */
            public int visitFieldEnd(final FieldEnd fieldEnd) throws Exception {
                if (fieldEnd.getFont().getHidden()) {
                    fieldEnd.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldSeparator node is encountered in the document.
             */
            public int visitFieldSeparator(final FieldSeparator fieldSeparator) throws Exception {
                if (fieldSeparator.getFont().getHidden()) {
                    fieldSeparator.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Run node is encountered in the document.
             */
            public int visitRun(final Run run) throws Exception {
                if (run.getFont().getHidden()) {
                    run.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Paragraph node is encountered in the document.
             */
            public int visitParagraphStart(final Paragraph paragraph) throws Exception {
                if (paragraph.getParagraphBreakFont().getHidden()) {
                    paragraph.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FormField is encountered in the document.
             */
            public int visitFormField(final FormField field) throws Exception {
                if (field.getFont().getHidden()) {
                    field.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a GroupShape is encountered in the document.
             */
            public int visitGroupShapeStart(final GroupShape groupShape) throws Exception {
                if (groupShape.getFont().getHidden()) {
                    groupShape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Shape is encountered in the document.
             */
            public int visitShapeStart(final Shape shape) throws Exception {
                if (shape.getFont().getHidden()) {
                    shape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Comment is encountered in the document.
             */
            public int visitCommentStart(final Comment comment) throws Exception {
                if (comment.getFont().getHidden()) {
                    comment.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Footnote is encountered in the document.
             */
            public int visitFootnoteStart(final Footnote footnote) throws Exception {
                if (footnote.getFont().getHidden()) {
                    footnote.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SpecialCharacter is encountered in the document.
            /// </summary>
            public /*override*/ /*VisitorAction*/int visitSpecialChar(SpecialChar specialChar) {
                if (specialChar.getFont().getHidden())
                    specialChar.remove();
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Table node is ended in the document.
             */
            public int visitTableEnd(final Table table) {
                // At the moment there is no way to tell if a particular Table/Row/Cell is hidden.
                // Instead, if the content of a table is hidden, then all inline child nodes of the table should be
                // hidden and thus removed by previous visits as well. This will result in the container being empty
                // so if this is the case we know to remove the table node.
                //
                // Note that a table which is not hidden but simply has no content will not be affected by this algorithm,
                // as technically they are not completely empty (for example a properly formed Cell will have at least 
                // an empty paragraph in it)
                if (!table.hasChildNodes()) {
                    table.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Cell node is ended in the document.
             */
            public int visitCellEnd(final Cell cell) {
                if (!cell.hasChildNodes() && cell.getParentNode() != null) {
                    cell.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Row node is ended in the document.
             */
            public int visitRowEnd(final Row row) {
                if (!row.hasChildNodes() && row.getParentNode() != null) {
                    row.remove();
                }
        
                return VisitorAction.CONTINUE;
            }

        Example:

        Shows how to create a group of shapes, and let it accept a visitor
        public void groupOfShapes() throws Exception {
            Document doc = new Document();
            DocumentBuilder builder = new DocumentBuilder(doc);
        
            // If you need to create "NonPrimitive" shapes, like SingleCornerSnipped, TopCornersSnipped, DiagonalCornersSnipped,
            // TopCornersOneRoundedOneSnipped, SingleCornerRounded, TopCornersRounded, DiagonalCornersRounded
            // please use DocumentBuilder.InsertShape methods
            Shape balloon = new Shape(doc, ShapeType.BALLOON);
            balloon.setWidth(200.0);
            balloon.setHeight(200.0);
            balloon.setStrokeColor(Color.RED);
        
            Shape cube = new Shape(doc, ShapeType.CUBE);
            cube.setWidth(100.0);
            cube.setHeight(100.0);
            cube.setStrokeColor(Color.BLUE);
        
            GroupShape group = new GroupShape(doc);
            group.appendChild(balloon);
            group.appendChild(cube);
        
            Assert.assertTrue(group.isGroup());
            builder.insertNode(group);
        
            ShapeInfoPrinter printer = new ShapeInfoPrinter();
            group.accept(printer);
        
            System.out.println(printer.getText());
        }
        
        /// <summary>
        /// Visitor that prints shape group contents information to the console.
        /// </summary>
        public static class ShapeInfoPrinter extends DocumentVisitor {
            public ShapeInfoPrinter() {
                mBuilder = new StringBuilder();
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            public int visitGroupShapeStart(final GroupShape groupShape) {
                mBuilder.append("Shape group started:\r\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitGroupShapeEnd(final GroupShape groupShape) {
                mBuilder.append("End of shape group\r\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitShapeStart(final Shape shape) {
                mBuilder.append("\tShape - " + shape.getShapeType() + ":\r\n");
                mBuilder.append("\t\tWidth: " + shape.getWidth() + "\r\n");
                mBuilder.append("\t\tHeight: " + shape.getHeight() + "\r\n");
                mBuilder.append("\t\tStroke color: " + shape.getStroke().getColor() + "\r\n");
                mBuilder.append("\t\tFill color: " + shape.getFill().getColor() + "\r\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitShapeEnd(final Shape shape) {
                mBuilder.append("\tEnd of shape\r\n");
                return VisitorAction.CONTINUE;
            }
        
            private StringBuilder mBuilder;
        }
      • visitHeaderFooterEnd

        public int visitHeaderFooterEnd(HeaderFooter headerFooter)
                                throws java.lang.Exception
        Called when enumeration of a header or footer in a section has ended.
        Parameters:
        headerFooter - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every header and footer in a document.
        public void headerFooterToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            HeaderFooterStructurePrinter visitor = new HeaderFooterStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        
            // An alternative way of accessing a document's header/footers section-by-section is by accessing the collection.
            HeaderFooter[] headerFooters = doc.getFirstSection().getHeadersFooters().toArray();
            Assert.assertEquals(3, headerFooters.length);
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered HeaderFooter nodes and their children.
        /// </summary>
        public static class HeaderFooterStructurePrinter extends DocumentVisitor {
            public HeaderFooterStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideHeaderFooter = false;
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideHeaderFooter) indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a HeaderFooter node is encountered in the document.
            /// </summary>
            public int visitHeaderFooterStart(final HeaderFooter headerFooter) {
                indentAndAppendLine("[HeaderFooter start] HeaderFooterType: " + headerFooter.getHeaderFooterType());
                mDocTraversalDepth++;
                mVisitorIsInsideHeaderFooter = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a HeaderFooter node have been visited.
            /// </summary>
            public int visitHeaderFooterEnd(final HeaderFooter headerFooter) {
                mDocTraversalDepth--;
                indentAndAppendLine("[HeaderFooter end]");
                mVisitorIsInsideHeaderFooter = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder, and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideHeaderFooter;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitHeaderFooterStart

        public int visitHeaderFooterStart(HeaderFooter headerFooter)
                                  throws java.lang.Exception
        Called when enumeration of a header or footer in a section has started.
        Parameters:
        headerFooter - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every header and footer in a document.
        public void headerFooterToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            HeaderFooterStructurePrinter visitor = new HeaderFooterStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        
            // An alternative way of accessing a document's header/footers section-by-section is by accessing the collection.
            HeaderFooter[] headerFooters = doc.getFirstSection().getHeadersFooters().toArray();
            Assert.assertEquals(3, headerFooters.length);
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered HeaderFooter nodes and their children.
        /// </summary>
        public static class HeaderFooterStructurePrinter extends DocumentVisitor {
            public HeaderFooterStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideHeaderFooter = false;
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideHeaderFooter) indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a HeaderFooter node is encountered in the document.
            /// </summary>
            public int visitHeaderFooterStart(final HeaderFooter headerFooter) {
                indentAndAppendLine("[HeaderFooter start] HeaderFooterType: " + headerFooter.getHeaderFooterType());
                mDocTraversalDepth++;
                mVisitorIsInsideHeaderFooter = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a HeaderFooter node have been visited.
            /// </summary>
            public int visitHeaderFooterEnd(final HeaderFooter headerFooter) {
                mDocTraversalDepth--;
                indentAndAppendLine("[HeaderFooter end]");
                mVisitorIsInsideHeaderFooter = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder, and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideHeaderFooter;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitOfficeMathEnd

        public int visitOfficeMathEnd(OfficeMath officeMath)
                              throws java.lang.Exception
        Called when enumeration of a Office Math object has ended.
        Parameters:
        officeMath - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every office math node in a document.
        public void officeMathToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            OfficeMathStructurePrinter visitor = new OfficeMathStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered OfficeMath nodes and their children.
        /// </summary>
        public static class OfficeMathStructurePrinter extends DocumentVisitor {
            public OfficeMathStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideOfficeMath = false;
            }
        
            /// <summary>
            /// Gets the plain text of the document that was accumulated by the visitor.
            /// </summary>
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideOfficeMath) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when an OfficeMath node is encountered in the document.
            /// </summary>
            public int visitOfficeMathStart(final OfficeMath officeMath) {
                indentAndAppendLine("[OfficeMath start] Math object type: " + officeMath.getMathObjectType());
                mDocTraversalDepth++;
                mVisitorIsInsideOfficeMath = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of an OfficeMath node have been visited.
            /// </summary>
            public int visitOfficeMathEnd(final OfficeMath officeMath) {
                mDocTraversalDepth--;
                indentAndAppendLine("[OfficeMath end]");
                mVisitorIsInsideOfficeMath = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideOfficeMath;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitOfficeMathStart

        public int visitOfficeMathStart(OfficeMath officeMath)
                                throws java.lang.Exception
        Called when enumeration of a Office Math object has started.
        Parameters:
        officeMath - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every office math node in a document.
        public void officeMathToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            OfficeMathStructurePrinter visitor = new OfficeMathStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered OfficeMath nodes and their children.
        /// </summary>
        public static class OfficeMathStructurePrinter extends DocumentVisitor {
            public OfficeMathStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideOfficeMath = false;
            }
        
            /// <summary>
            /// Gets the plain text of the document that was accumulated by the visitor.
            /// </summary>
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideOfficeMath) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when an OfficeMath node is encountered in the document.
            /// </summary>
            public int visitOfficeMathStart(final OfficeMath officeMath) {
                indentAndAppendLine("[OfficeMath start] Math object type: " + officeMath.getMathObjectType());
                mDocTraversalDepth++;
                mVisitorIsInsideOfficeMath = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of an OfficeMath node have been visited.
            /// </summary>
            public int visitOfficeMathEnd(final OfficeMath officeMath) {
                mDocTraversalDepth--;
                indentAndAppendLine("[OfficeMath end]");
                mVisitorIsInsideOfficeMath = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideOfficeMath;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitParagraphEnd

        public int visitParagraphEnd(Paragraph paragraph)
                             throws java.lang.Exception
        Called when enumeration of a paragraph has ended.
        Parameters:
        paragraph - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to use a document visitor to print a document's node structure.
        public void docStructureToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            DocStructurePrinter visitor = new DocStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's tree of child nodes, and creates a map of this tree in the form of a string.
        /// </summary>
        public static class DocStructurePrinter extends DocumentVisitor {
            public DocStructurePrinter() {
                mAcceptingNodeChildTree = new StringBuilder();
            }
        
            public String getText() {
                return mAcceptingNodeChildTree.toString();
            }
        
            /// <summary>
            /// Called when a Document node is encountered.
            /// </summary>
            public int visitDocumentStart(Document doc) {
                int childNodeCount = doc.getChildNodes(NodeType.ANY, true).getCount();
        
                indentAndAppendLine("[Document start] Child nodes: " + childNodeCount);
                mDocTraversalDepth++;
        
                // Allow the visitor to continue visiting other nodes.
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Document node have been visited.
            /// </summary>
            public int visitDocumentEnd(Document doc) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Document end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Section node is encountered in the document.
            /// </summary>
            public int visitSectionStart(final Section section) {
                // Get the index of our section within the document
                NodeCollection docSections = section.getDocument().getChildNodes(NodeType.SECTION, false);
                int sectionIndex = docSections.indexOf(section);
        
                indentAndAppendLine("[Section start] Section index: " + sectionIndex);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Section node have been visited.
            /// </summary>
            public int visitSectionEnd(final Section section) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Section end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Body node is encountered in the document.
            /// </summary>
            public int visitBodyStart(final Body body) {
                int paragraphCount = body.getParagraphs().getCount();
                indentAndAppendLine("[Body start] Paragraphs: " + paragraphCount);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Body node have been visited.
            /// </summary>
            public int visitBodyEnd(final Body body) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Body end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Paragraph node is encountered in the document.
            /// </summary>
            public int visitParagraphStart(final Paragraph paragraph) {
                indentAndAppendLine("[Paragraph start]");
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Paragraph node have been visited.
            /// </summary>
            public int visitParagraphEnd(final Paragraph paragraph) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Paragraph end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SubDocument node is encountered in the document.
            /// </summary>
            public int visitSubDocument(final SubDocument subDocument) {
                indentAndAppendLine("[SubDocument]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mAcceptingNodeChildTree.append("|  ");
                }
        
                mAcceptingNodeChildTree.append(text + "\r\n");
            }
        
            private int mDocTraversalDepth;
            private StringBuilder mAcceptingNodeChildTree;
        }
      • visitParagraphStart

        public int visitParagraphStart(Paragraph paragraph)
                               throws java.lang.Exception
        Called when enumeration of a paragraph has started.
        Parameters:
        paragraph - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Implements the Visitor Pattern to remove all content formatted as hidden from the document.
        public void removeHiddenContentFromDocument() throws Exception {
            // Open the document we want to remove hidden content from
            Document doc = new Document(getMyDir() + "Hidden content.docx");
        
            // Create an object that inherits from the DocumentVisitor class
            RemoveHiddenContentVisitor hiddenContentRemover = new RemoveHiddenContentVisitor();
        
            // This is the well known Visitor pattern. Get the model to accept a visitor
            // The model will iterate through itself by calling the corresponding methods
            // on the visitor object (this is called visiting)
        
            // We can run it over the entire the document like so
            doc.accept(hiddenContentRemover);
        
            // Or we can run it on only a specific node
            Paragraph para = (Paragraph) doc.getChild(NodeType.PARAGRAPH, 4, true);
            para.accept(hiddenContentRemover);
        
            // Or over a different type of node like below
            Table table = (Table) doc.getChild(NodeType.TABLE, 0, true);
            table.accept(hiddenContentRemover);
        
            doc.save(getArtifactsDir() + "Font.RemoveHiddenContentFromDocument.docx");
        }
        
        /**
         * This class when executed will remove all hidden content from the Document. Implemented as a Visitor.
         */
        private class RemoveHiddenContentVisitor extends DocumentVisitor {
            /**
             * Called when a FieldStart node is encountered in the document.
             */
            public int visitFieldStart(final FieldStart fieldStart) throws Exception {
                // If this node is hidden, then remove it
                if (fieldStart.getFont().getHidden()) {
                    fieldStart.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldEnd node is encountered in the document.
             */
            public int visitFieldEnd(final FieldEnd fieldEnd) throws Exception {
                if (fieldEnd.getFont().getHidden()) {
                    fieldEnd.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldSeparator node is encountered in the document.
             */
            public int visitFieldSeparator(final FieldSeparator fieldSeparator) throws Exception {
                if (fieldSeparator.getFont().getHidden()) {
                    fieldSeparator.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Run node is encountered in the document.
             */
            public int visitRun(final Run run) throws Exception {
                if (run.getFont().getHidden()) {
                    run.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Paragraph node is encountered in the document.
             */
            public int visitParagraphStart(final Paragraph paragraph) throws Exception {
                if (paragraph.getParagraphBreakFont().getHidden()) {
                    paragraph.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FormField is encountered in the document.
             */
            public int visitFormField(final FormField field) throws Exception {
                if (field.getFont().getHidden()) {
                    field.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a GroupShape is encountered in the document.
             */
            public int visitGroupShapeStart(final GroupShape groupShape) throws Exception {
                if (groupShape.getFont().getHidden()) {
                    groupShape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Shape is encountered in the document.
             */
            public int visitShapeStart(final Shape shape) throws Exception {
                if (shape.getFont().getHidden()) {
                    shape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Comment is encountered in the document.
             */
            public int visitCommentStart(final Comment comment) throws Exception {
                if (comment.getFont().getHidden()) {
                    comment.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Footnote is encountered in the document.
             */
            public int visitFootnoteStart(final Footnote footnote) throws Exception {
                if (footnote.getFont().getHidden()) {
                    footnote.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SpecialCharacter is encountered in the document.
            /// </summary>
            public /*override*/ /*VisitorAction*/int visitSpecialChar(SpecialChar specialChar) {
                if (specialChar.getFont().getHidden())
                    specialChar.remove();
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Table node is ended in the document.
             */
            public int visitTableEnd(final Table table) {
                // At the moment there is no way to tell if a particular Table/Row/Cell is hidden.
                // Instead, if the content of a table is hidden, then all inline child nodes of the table should be
                // hidden and thus removed by previous visits as well. This will result in the container being empty
                // so if this is the case we know to remove the table node.
                //
                // Note that a table which is not hidden but simply has no content will not be affected by this algorithm,
                // as technically they are not completely empty (for example a properly formed Cell will have at least 
                // an empty paragraph in it)
                if (!table.hasChildNodes()) {
                    table.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Cell node is ended in the document.
             */
            public int visitCellEnd(final Cell cell) {
                if (!cell.hasChildNodes() && cell.getParentNode() != null) {
                    cell.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Row node is ended in the document.
             */
            public int visitRowEnd(final Row row) {
                if (!row.hasChildNodes() && row.getParentNode() != null) {
                    row.remove();
                }
        
                return VisitorAction.CONTINUE;
            }

        Example:

        Shows how to use a document visitor to print a document's node structure.
        public void docStructureToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            DocStructurePrinter visitor = new DocStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's tree of child nodes, and creates a map of this tree in the form of a string.
        /// </summary>
        public static class DocStructurePrinter extends DocumentVisitor {
            public DocStructurePrinter() {
                mAcceptingNodeChildTree = new StringBuilder();
            }
        
            public String getText() {
                return mAcceptingNodeChildTree.toString();
            }
        
            /// <summary>
            /// Called when a Document node is encountered.
            /// </summary>
            public int visitDocumentStart(Document doc) {
                int childNodeCount = doc.getChildNodes(NodeType.ANY, true).getCount();
        
                indentAndAppendLine("[Document start] Child nodes: " + childNodeCount);
                mDocTraversalDepth++;
        
                // Allow the visitor to continue visiting other nodes.
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Document node have been visited.
            /// </summary>
            public int visitDocumentEnd(Document doc) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Document end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Section node is encountered in the document.
            /// </summary>
            public int visitSectionStart(final Section section) {
                // Get the index of our section within the document
                NodeCollection docSections = section.getDocument().getChildNodes(NodeType.SECTION, false);
                int sectionIndex = docSections.indexOf(section);
        
                indentAndAppendLine("[Section start] Section index: " + sectionIndex);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Section node have been visited.
            /// </summary>
            public int visitSectionEnd(final Section section) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Section end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Body node is encountered in the document.
            /// </summary>
            public int visitBodyStart(final Body body) {
                int paragraphCount = body.getParagraphs().getCount();
                indentAndAppendLine("[Body start] Paragraphs: " + paragraphCount);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Body node have been visited.
            /// </summary>
            public int visitBodyEnd(final Body body) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Body end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Paragraph node is encountered in the document.
            /// </summary>
            public int visitParagraphStart(final Paragraph paragraph) {
                indentAndAppendLine("[Paragraph start]");
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Paragraph node have been visited.
            /// </summary>
            public int visitParagraphEnd(final Paragraph paragraph) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Paragraph end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SubDocument node is encountered in the document.
            /// </summary>
            public int visitSubDocument(final SubDocument subDocument) {
                indentAndAppendLine("[SubDocument]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mAcceptingNodeChildTree.append("|  ");
                }
        
                mAcceptingNodeChildTree.append(text + "\r\n");
            }
        
            private int mDocTraversalDepth;
            private StringBuilder mAcceptingNodeChildTree;
        }
      • visitRowEnd

        public int visitRowEnd(Row row)
                       throws java.lang.Exception
        Called when enumeration of a table row has ended.
        Parameters:
        row - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Implements the Visitor Pattern to remove all content formatted as hidden from the document.
        public void removeHiddenContentFromDocument() throws Exception {
            // Open the document we want to remove hidden content from
            Document doc = new Document(getMyDir() + "Hidden content.docx");
        
            // Create an object that inherits from the DocumentVisitor class
            RemoveHiddenContentVisitor hiddenContentRemover = new RemoveHiddenContentVisitor();
        
            // This is the well known Visitor pattern. Get the model to accept a visitor
            // The model will iterate through itself by calling the corresponding methods
            // on the visitor object (this is called visiting)
        
            // We can run it over the entire the document like so
            doc.accept(hiddenContentRemover);
        
            // Or we can run it on only a specific node
            Paragraph para = (Paragraph) doc.getChild(NodeType.PARAGRAPH, 4, true);
            para.accept(hiddenContentRemover);
        
            // Or over a different type of node like below
            Table table = (Table) doc.getChild(NodeType.TABLE, 0, true);
            table.accept(hiddenContentRemover);
        
            doc.save(getArtifactsDir() + "Font.RemoveHiddenContentFromDocument.docx");
        }
        
        /**
         * This class when executed will remove all hidden content from the Document. Implemented as a Visitor.
         */
        private class RemoveHiddenContentVisitor extends DocumentVisitor {
            /**
             * Called when a FieldStart node is encountered in the document.
             */
            public int visitFieldStart(final FieldStart fieldStart) throws Exception {
                // If this node is hidden, then remove it
                if (fieldStart.getFont().getHidden()) {
                    fieldStart.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldEnd node is encountered in the document.
             */
            public int visitFieldEnd(final FieldEnd fieldEnd) throws Exception {
                if (fieldEnd.getFont().getHidden()) {
                    fieldEnd.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldSeparator node is encountered in the document.
             */
            public int visitFieldSeparator(final FieldSeparator fieldSeparator) throws Exception {
                if (fieldSeparator.getFont().getHidden()) {
                    fieldSeparator.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Run node is encountered in the document.
             */
            public int visitRun(final Run run) throws Exception {
                if (run.getFont().getHidden()) {
                    run.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Paragraph node is encountered in the document.
             */
            public int visitParagraphStart(final Paragraph paragraph) throws Exception {
                if (paragraph.getParagraphBreakFont().getHidden()) {
                    paragraph.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FormField is encountered in the document.
             */
            public int visitFormField(final FormField field) throws Exception {
                if (field.getFont().getHidden()) {
                    field.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a GroupShape is encountered in the document.
             */
            public int visitGroupShapeStart(final GroupShape groupShape) throws Exception {
                if (groupShape.getFont().getHidden()) {
                    groupShape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Shape is encountered in the document.
             */
            public int visitShapeStart(final Shape shape) throws Exception {
                if (shape.getFont().getHidden()) {
                    shape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Comment is encountered in the document.
             */
            public int visitCommentStart(final Comment comment) throws Exception {
                if (comment.getFont().getHidden()) {
                    comment.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Footnote is encountered in the document.
             */
            public int visitFootnoteStart(final Footnote footnote) throws Exception {
                if (footnote.getFont().getHidden()) {
                    footnote.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SpecialCharacter is encountered in the document.
            /// </summary>
            public /*override*/ /*VisitorAction*/int visitSpecialChar(SpecialChar specialChar) {
                if (specialChar.getFont().getHidden())
                    specialChar.remove();
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Table node is ended in the document.
             */
            public int visitTableEnd(final Table table) {
                // At the moment there is no way to tell if a particular Table/Row/Cell is hidden.
                // Instead, if the content of a table is hidden, then all inline child nodes of the table should be
                // hidden and thus removed by previous visits as well. This will result in the container being empty
                // so if this is the case we know to remove the table node.
                //
                // Note that a table which is not hidden but simply has no content will not be affected by this algorithm,
                // as technically they are not completely empty (for example a properly formed Cell will have at least 
                // an empty paragraph in it)
                if (!table.hasChildNodes()) {
                    table.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Cell node is ended in the document.
             */
            public int visitCellEnd(final Cell cell) {
                if (!cell.hasChildNodes() && cell.getParentNode() != null) {
                    cell.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Row node is ended in the document.
             */
            public int visitRowEnd(final Row row) {
                if (!row.hasChildNodes() && row.getParentNode() != null) {
                    row.remove();
                }
        
                return VisitorAction.CONTINUE;
            }

        Example:

        Shows how to print the node structure of every table in a document.
        public void tableToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            TableStructurePrinter visitor = new TableStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered Table nodes and their children.
        /// </summary>
        public static class TableStructurePrinter extends DocumentVisitor {
            public TableStructurePrinter() {
                mVisitedTables = new StringBuilder();
                mVisitorIsInsideTable = false;
            }
        
            public String getText() {
                return mVisitedTables.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// Runs that are not within tables are not recorded.
            /// </summary>
            public /*override*/ /*VisitorAction*/int visitRun(Run run) {
                if (mVisitorIsInsideTable) indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Table is encountered in the document.
            /// </summary>
            public int visitTableStart(final Table table) {
                int rows = 0;
                int columns = 0;
        
                if (table.getRows().getCount() > 0) {
                    rows = table.getRows().getCount();
                    columns = table.getFirstRow().getCount();
                }
        
                indentAndAppendLine("[Table start] Size: " + rows + "x" + columns);
                mDocTraversalDepth++;
                mVisitorIsInsideTable = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Table node have been visited.
            /// </summary>
            public int visitTableEnd(final Table table) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Table end]");
                mVisitorIsInsideTable = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Row node is encountered in the document.
            /// </summary>
            public int visitRowStart(final Row row) {
                String rowContents = row.getText().replaceAll("\\u0007", ", ").replaceAll(", , ", "");
                int rowWidth = row.indexOf(row.getLastCell()) + 1;
                int rowIndex = row.getParentTable().indexOf(row);
                String rowStatusInTable = row.isFirstRow() && row.isLastRow() ? "only" : row.isFirstRow() ? "first" : row.isLastRow() ? "last" : "";
                if (!"".equals(rowStatusInTable)) {
                    rowStatusInTable = MessageFormat.format(", the {0} row in this table,", rowStatusInTable);
                }
        
                indentAndAppendLine(MessageFormat.format("[Row start] Row #{0}{1} width {2}, \"{3}\"", ++rowIndex, rowStatusInTable, rowWidth, rowContents));
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Row node have been visited.
            /// </summary>
            public int visitRowEnd(final Row row) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Row end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Cell node is encountered in the document.
            /// </summary>
            public int visitCellStart(final Cell cell) {
                Row row = cell.getParentRow();
                Table table = row.getParentTable();
                String cellStatusInRow = cell.isFirstCell() && cell.isLastCell() ? "only" : cell.isFirstCell() ? "first" : cell.isLastCell() ? "last" : "";
                if (!"".equals(cellStatusInRow)) {
                    cellStatusInRow = MessageFormat.format(", the {0} cell in this row", cellStatusInRow);
                }
        
                indentAndAppendLine(MessageFormat.format("[Cell start] Row {0}, Col {1}{2}", table.indexOf(row) + 1, row.indexOf(cell) + 1, cellStatusInRow));
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Cell node have been visited.
            /// </summary>
            public int visitCellEnd(final Cell cell) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Cell end]");
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder, and indent it depending on how deep the visitor is
            /// into the current table's tree of child nodes.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mVisitedTables.append("|  ");
                }
        
                mVisitedTables.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideTable;
            private int mDocTraversalDepth;
            private /*final*/ StringBuilder mVisitedTables;
        }
      • visitRowStart

        public int visitRowStart(Row row)
                         throws java.lang.Exception
        Called when enumeration of a table row has started.
        Parameters:
        row - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every table in a document.
        public void tableToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            TableStructurePrinter visitor = new TableStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered Table nodes and their children.
        /// </summary>
        public static class TableStructurePrinter extends DocumentVisitor {
            public TableStructurePrinter() {
                mVisitedTables = new StringBuilder();
                mVisitorIsInsideTable = false;
            }
        
            public String getText() {
                return mVisitedTables.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// Runs that are not within tables are not recorded.
            /// </summary>
            public /*override*/ /*VisitorAction*/int visitRun(Run run) {
                if (mVisitorIsInsideTable) indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Table is encountered in the document.
            /// </summary>
            public int visitTableStart(final Table table) {
                int rows = 0;
                int columns = 0;
        
                if (table.getRows().getCount() > 0) {
                    rows = table.getRows().getCount();
                    columns = table.getFirstRow().getCount();
                }
        
                indentAndAppendLine("[Table start] Size: " + rows + "x" + columns);
                mDocTraversalDepth++;
                mVisitorIsInsideTable = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Table node have been visited.
            /// </summary>
            public int visitTableEnd(final Table table) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Table end]");
                mVisitorIsInsideTable = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Row node is encountered in the document.
            /// </summary>
            public int visitRowStart(final Row row) {
                String rowContents = row.getText().replaceAll("\\u0007", ", ").replaceAll(", , ", "");
                int rowWidth = row.indexOf(row.getLastCell()) + 1;
                int rowIndex = row.getParentTable().indexOf(row);
                String rowStatusInTable = row.isFirstRow() && row.isLastRow() ? "only" : row.isFirstRow() ? "first" : row.isLastRow() ? "last" : "";
                if (!"".equals(rowStatusInTable)) {
                    rowStatusInTable = MessageFormat.format(", the {0} row in this table,", rowStatusInTable);
                }
        
                indentAndAppendLine(MessageFormat.format("[Row start] Row #{0}{1} width {2}, \"{3}\"", ++rowIndex, rowStatusInTable, rowWidth, rowContents));
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Row node have been visited.
            /// </summary>
            public int visitRowEnd(final Row row) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Row end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Cell node is encountered in the document.
            /// </summary>
            public int visitCellStart(final Cell cell) {
                Row row = cell.getParentRow();
                Table table = row.getParentTable();
                String cellStatusInRow = cell.isFirstCell() && cell.isLastCell() ? "only" : cell.isFirstCell() ? "first" : cell.isLastCell() ? "last" : "";
                if (!"".equals(cellStatusInRow)) {
                    cellStatusInRow = MessageFormat.format(", the {0} cell in this row", cellStatusInRow);
                }
        
                indentAndAppendLine(MessageFormat.format("[Cell start] Row {0}, Col {1}{2}", table.indexOf(row) + 1, row.indexOf(cell) + 1, cellStatusInRow));
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Cell node have been visited.
            /// </summary>
            public int visitCellEnd(final Cell cell) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Cell end]");
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder, and indent it depending on how deep the visitor is
            /// into the current table's tree of child nodes.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mVisitedTables.append("|  ");
                }
        
                mVisitedTables.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideTable;
            private int mDocTraversalDepth;
            private /*final*/ StringBuilder mVisitedTables;
        }
      • visitRun

        public int visitRun(Run run)
                    throws java.lang.Exception
        Called when a run of text in the is encountered.
        Parameters:
        run - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to use a document visitor to print a document's node structure.
        public void docStructureToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            DocStructurePrinter visitor = new DocStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's tree of child nodes, and creates a map of this tree in the form of a string.
        /// </summary>
        public static class DocStructurePrinter extends DocumentVisitor {
            public DocStructurePrinter() {
                mAcceptingNodeChildTree = new StringBuilder();
            }
        
            public String getText() {
                return mAcceptingNodeChildTree.toString();
            }
        
            /// <summary>
            /// Called when a Document node is encountered.
            /// </summary>
            public int visitDocumentStart(Document doc) {
                int childNodeCount = doc.getChildNodes(NodeType.ANY, true).getCount();
        
                indentAndAppendLine("[Document start] Child nodes: " + childNodeCount);
                mDocTraversalDepth++;
        
                // Allow the visitor to continue visiting other nodes.
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Document node have been visited.
            /// </summary>
            public int visitDocumentEnd(Document doc) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Document end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Section node is encountered in the document.
            /// </summary>
            public int visitSectionStart(final Section section) {
                // Get the index of our section within the document
                NodeCollection docSections = section.getDocument().getChildNodes(NodeType.SECTION, false);
                int sectionIndex = docSections.indexOf(section);
        
                indentAndAppendLine("[Section start] Section index: " + sectionIndex);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Section node have been visited.
            /// </summary>
            public int visitSectionEnd(final Section section) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Section end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Body node is encountered in the document.
            /// </summary>
            public int visitBodyStart(final Body body) {
                int paragraphCount = body.getParagraphs().getCount();
                indentAndAppendLine("[Body start] Paragraphs: " + paragraphCount);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Body node have been visited.
            /// </summary>
            public int visitBodyEnd(final Body body) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Body end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Paragraph node is encountered in the document.
            /// </summary>
            public int visitParagraphStart(final Paragraph paragraph) {
                indentAndAppendLine("[Paragraph start]");
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Paragraph node have been visited.
            /// </summary>
            public int visitParagraphEnd(final Paragraph paragraph) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Paragraph end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SubDocument node is encountered in the document.
            /// </summary>
            public int visitSubDocument(final SubDocument subDocument) {
                indentAndAppendLine("[SubDocument]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mAcceptingNodeChildTree.append("|  ");
                }
        
                mAcceptingNodeChildTree.append(text + "\r\n");
            }
        
            private int mDocTraversalDepth;
            private StringBuilder mAcceptingNodeChildTree;
        }
      • visitSectionEnd

        public int visitSectionEnd(Section section)
                           throws java.lang.Exception
        Called when enumeration of a section has ended.
        Parameters:
        section - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to use a document visitor to print a document's node structure.
        public void docStructureToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            DocStructurePrinter visitor = new DocStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's tree of child nodes, and creates a map of this tree in the form of a string.
        /// </summary>
        public static class DocStructurePrinter extends DocumentVisitor {
            public DocStructurePrinter() {
                mAcceptingNodeChildTree = new StringBuilder();
            }
        
            public String getText() {
                return mAcceptingNodeChildTree.toString();
            }
        
            /// <summary>
            /// Called when a Document node is encountered.
            /// </summary>
            public int visitDocumentStart(Document doc) {
                int childNodeCount = doc.getChildNodes(NodeType.ANY, true).getCount();
        
                indentAndAppendLine("[Document start] Child nodes: " + childNodeCount);
                mDocTraversalDepth++;
        
                // Allow the visitor to continue visiting other nodes.
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Document node have been visited.
            /// </summary>
            public int visitDocumentEnd(Document doc) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Document end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Section node is encountered in the document.
            /// </summary>
            public int visitSectionStart(final Section section) {
                // Get the index of our section within the document
                NodeCollection docSections = section.getDocument().getChildNodes(NodeType.SECTION, false);
                int sectionIndex = docSections.indexOf(section);
        
                indentAndAppendLine("[Section start] Section index: " + sectionIndex);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Section node have been visited.
            /// </summary>
            public int visitSectionEnd(final Section section) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Section end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Body node is encountered in the document.
            /// </summary>
            public int visitBodyStart(final Body body) {
                int paragraphCount = body.getParagraphs().getCount();
                indentAndAppendLine("[Body start] Paragraphs: " + paragraphCount);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Body node have been visited.
            /// </summary>
            public int visitBodyEnd(final Body body) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Body end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Paragraph node is encountered in the document.
            /// </summary>
            public int visitParagraphStart(final Paragraph paragraph) {
                indentAndAppendLine("[Paragraph start]");
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Paragraph node have been visited.
            /// </summary>
            public int visitParagraphEnd(final Paragraph paragraph) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Paragraph end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SubDocument node is encountered in the document.
            /// </summary>
            public int visitSubDocument(final SubDocument subDocument) {
                indentAndAppendLine("[SubDocument]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mAcceptingNodeChildTree.append("|  ");
                }
        
                mAcceptingNodeChildTree.append(text + "\r\n");
            }
        
            private int mDocTraversalDepth;
            private StringBuilder mAcceptingNodeChildTree;
        }
      • visitSectionStart

        public int visitSectionStart(Section section)
                             throws java.lang.Exception
        Called when enumeration of a section has started.
        Parameters:
        section - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to use a document visitor to print a document's node structure.
        public void docStructureToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            DocStructurePrinter visitor = new DocStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's tree of child nodes, and creates a map of this tree in the form of a string.
        /// </summary>
        public static class DocStructurePrinter extends DocumentVisitor {
            public DocStructurePrinter() {
                mAcceptingNodeChildTree = new StringBuilder();
            }
        
            public String getText() {
                return mAcceptingNodeChildTree.toString();
            }
        
            /// <summary>
            /// Called when a Document node is encountered.
            /// </summary>
            public int visitDocumentStart(Document doc) {
                int childNodeCount = doc.getChildNodes(NodeType.ANY, true).getCount();
        
                indentAndAppendLine("[Document start] Child nodes: " + childNodeCount);
                mDocTraversalDepth++;
        
                // Allow the visitor to continue visiting other nodes.
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Document node have been visited.
            /// </summary>
            public int visitDocumentEnd(Document doc) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Document end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Section node is encountered in the document.
            /// </summary>
            public int visitSectionStart(final Section section) {
                // Get the index of our section within the document
                NodeCollection docSections = section.getDocument().getChildNodes(NodeType.SECTION, false);
                int sectionIndex = docSections.indexOf(section);
        
                indentAndAppendLine("[Section start] Section index: " + sectionIndex);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Section node have been visited.
            /// </summary>
            public int visitSectionEnd(final Section section) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Section end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Body node is encountered in the document.
            /// </summary>
            public int visitBodyStart(final Body body) {
                int paragraphCount = body.getParagraphs().getCount();
                indentAndAppendLine("[Body start] Paragraphs: " + paragraphCount);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Body node have been visited.
            /// </summary>
            public int visitBodyEnd(final Body body) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Body end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Paragraph node is encountered in the document.
            /// </summary>
            public int visitParagraphStart(final Paragraph paragraph) {
                indentAndAppendLine("[Paragraph start]");
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Paragraph node have been visited.
            /// </summary>
            public int visitParagraphEnd(final Paragraph paragraph) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Paragraph end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SubDocument node is encountered in the document.
            /// </summary>
            public int visitSubDocument(final SubDocument subDocument) {
                indentAndAppendLine("[SubDocument]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mAcceptingNodeChildTree.append("|  ");
                }
        
                mAcceptingNodeChildTree.append(text + "\r\n");
            }
        
            private int mDocTraversalDepth;
            private StringBuilder mAcceptingNodeChildTree;
        }
      • visitShapeEnd

        public int visitShapeEnd(Shape shape)
                         throws java.lang.Exception
        Called when enumeration of a shape has ended.
        Parameters:
        shape - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to create a group of shapes, and let it accept a visitor
        public void groupOfShapes() throws Exception {
            Document doc = new Document();
            DocumentBuilder builder = new DocumentBuilder(doc);
        
            // If you need to create "NonPrimitive" shapes, like SingleCornerSnipped, TopCornersSnipped, DiagonalCornersSnipped,
            // TopCornersOneRoundedOneSnipped, SingleCornerRounded, TopCornersRounded, DiagonalCornersRounded
            // please use DocumentBuilder.InsertShape methods
            Shape balloon = new Shape(doc, ShapeType.BALLOON);
            balloon.setWidth(200.0);
            balloon.setHeight(200.0);
            balloon.setStrokeColor(Color.RED);
        
            Shape cube = new Shape(doc, ShapeType.CUBE);
            cube.setWidth(100.0);
            cube.setHeight(100.0);
            cube.setStrokeColor(Color.BLUE);
        
            GroupShape group = new GroupShape(doc);
            group.appendChild(balloon);
            group.appendChild(cube);
        
            Assert.assertTrue(group.isGroup());
            builder.insertNode(group);
        
            ShapeInfoPrinter printer = new ShapeInfoPrinter();
            group.accept(printer);
        
            System.out.println(printer.getText());
        }
        
        /// <summary>
        /// Visitor that prints shape group contents information to the console.
        /// </summary>
        public static class ShapeInfoPrinter extends DocumentVisitor {
            public ShapeInfoPrinter() {
                mBuilder = new StringBuilder();
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            public int visitGroupShapeStart(final GroupShape groupShape) {
                mBuilder.append("Shape group started:\r\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitGroupShapeEnd(final GroupShape groupShape) {
                mBuilder.append("End of shape group\r\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitShapeStart(final Shape shape) {
                mBuilder.append("\tShape - " + shape.getShapeType() + ":\r\n");
                mBuilder.append("\t\tWidth: " + shape.getWidth() + "\r\n");
                mBuilder.append("\t\tHeight: " + shape.getHeight() + "\r\n");
                mBuilder.append("\t\tStroke color: " + shape.getStroke().getColor() + "\r\n");
                mBuilder.append("\t\tFill color: " + shape.getFill().getColor() + "\r\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitShapeEnd(final Shape shape) {
                mBuilder.append("\tEnd of shape\r\n");
                return VisitorAction.CONTINUE;
            }
        
            private StringBuilder mBuilder;
        }
      • visitShapeStart

        public int visitShapeStart(Shape shape)
                           throws java.lang.Exception
        Called when enumeration of a shape has started.
        Parameters:
        shape - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Implements the Visitor Pattern to remove all content formatted as hidden from the document.
        public void removeHiddenContentFromDocument() throws Exception {
            // Open the document we want to remove hidden content from
            Document doc = new Document(getMyDir() + "Hidden content.docx");
        
            // Create an object that inherits from the DocumentVisitor class
            RemoveHiddenContentVisitor hiddenContentRemover = new RemoveHiddenContentVisitor();
        
            // This is the well known Visitor pattern. Get the model to accept a visitor
            // The model will iterate through itself by calling the corresponding methods
            // on the visitor object (this is called visiting)
        
            // We can run it over the entire the document like so
            doc.accept(hiddenContentRemover);
        
            // Or we can run it on only a specific node
            Paragraph para = (Paragraph) doc.getChild(NodeType.PARAGRAPH, 4, true);
            para.accept(hiddenContentRemover);
        
            // Or over a different type of node like below
            Table table = (Table) doc.getChild(NodeType.TABLE, 0, true);
            table.accept(hiddenContentRemover);
        
            doc.save(getArtifactsDir() + "Font.RemoveHiddenContentFromDocument.docx");
        }
        
        /**
         * This class when executed will remove all hidden content from the Document. Implemented as a Visitor.
         */
        private class RemoveHiddenContentVisitor extends DocumentVisitor {
            /**
             * Called when a FieldStart node is encountered in the document.
             */
            public int visitFieldStart(final FieldStart fieldStart) throws Exception {
                // If this node is hidden, then remove it
                if (fieldStart.getFont().getHidden()) {
                    fieldStart.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldEnd node is encountered in the document.
             */
            public int visitFieldEnd(final FieldEnd fieldEnd) throws Exception {
                if (fieldEnd.getFont().getHidden()) {
                    fieldEnd.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldSeparator node is encountered in the document.
             */
            public int visitFieldSeparator(final FieldSeparator fieldSeparator) throws Exception {
                if (fieldSeparator.getFont().getHidden()) {
                    fieldSeparator.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Run node is encountered in the document.
             */
            public int visitRun(final Run run) throws Exception {
                if (run.getFont().getHidden()) {
                    run.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Paragraph node is encountered in the document.
             */
            public int visitParagraphStart(final Paragraph paragraph) throws Exception {
                if (paragraph.getParagraphBreakFont().getHidden()) {
                    paragraph.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FormField is encountered in the document.
             */
            public int visitFormField(final FormField field) throws Exception {
                if (field.getFont().getHidden()) {
                    field.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a GroupShape is encountered in the document.
             */
            public int visitGroupShapeStart(final GroupShape groupShape) throws Exception {
                if (groupShape.getFont().getHidden()) {
                    groupShape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Shape is encountered in the document.
             */
            public int visitShapeStart(final Shape shape) throws Exception {
                if (shape.getFont().getHidden()) {
                    shape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Comment is encountered in the document.
             */
            public int visitCommentStart(final Comment comment) throws Exception {
                if (comment.getFont().getHidden()) {
                    comment.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Footnote is encountered in the document.
             */
            public int visitFootnoteStart(final Footnote footnote) throws Exception {
                if (footnote.getFont().getHidden()) {
                    footnote.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SpecialCharacter is encountered in the document.
            /// </summary>
            public /*override*/ /*VisitorAction*/int visitSpecialChar(SpecialChar specialChar) {
                if (specialChar.getFont().getHidden())
                    specialChar.remove();
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Table node is ended in the document.
             */
            public int visitTableEnd(final Table table) {
                // At the moment there is no way to tell if a particular Table/Row/Cell is hidden.
                // Instead, if the content of a table is hidden, then all inline child nodes of the table should be
                // hidden and thus removed by previous visits as well. This will result in the container being empty
                // so if this is the case we know to remove the table node.
                //
                // Note that a table which is not hidden but simply has no content will not be affected by this algorithm,
                // as technically they are not completely empty (for example a properly formed Cell will have at least 
                // an empty paragraph in it)
                if (!table.hasChildNodes()) {
                    table.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Cell node is ended in the document.
             */
            public int visitCellEnd(final Cell cell) {
                if (!cell.hasChildNodes() && cell.getParentNode() != null) {
                    cell.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Row node is ended in the document.
             */
            public int visitRowEnd(final Row row) {
                if (!row.hasChildNodes() && row.getParentNode() != null) {
                    row.remove();
                }
        
                return VisitorAction.CONTINUE;
            }

        Example:

        Shows how to create a group of shapes, and let it accept a visitor
        public void groupOfShapes() throws Exception {
            Document doc = new Document();
            DocumentBuilder builder = new DocumentBuilder(doc);
        
            // If you need to create "NonPrimitive" shapes, like SingleCornerSnipped, TopCornersSnipped, DiagonalCornersSnipped,
            // TopCornersOneRoundedOneSnipped, SingleCornerRounded, TopCornersRounded, DiagonalCornersRounded
            // please use DocumentBuilder.InsertShape methods
            Shape balloon = new Shape(doc, ShapeType.BALLOON);
            balloon.setWidth(200.0);
            balloon.setHeight(200.0);
            balloon.setStrokeColor(Color.RED);
        
            Shape cube = new Shape(doc, ShapeType.CUBE);
            cube.setWidth(100.0);
            cube.setHeight(100.0);
            cube.setStrokeColor(Color.BLUE);
        
            GroupShape group = new GroupShape(doc);
            group.appendChild(balloon);
            group.appendChild(cube);
        
            Assert.assertTrue(group.isGroup());
            builder.insertNode(group);
        
            ShapeInfoPrinter printer = new ShapeInfoPrinter();
            group.accept(printer);
        
            System.out.println(printer.getText());
        }
        
        /// <summary>
        /// Visitor that prints shape group contents information to the console.
        /// </summary>
        public static class ShapeInfoPrinter extends DocumentVisitor {
            public ShapeInfoPrinter() {
                mBuilder = new StringBuilder();
            }
        
            public String getText() {
                return mBuilder.toString();
            }
        
            public int visitGroupShapeStart(final GroupShape groupShape) {
                mBuilder.append("Shape group started:\r\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitGroupShapeEnd(final GroupShape groupShape) {
                mBuilder.append("End of shape group\r\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitShapeStart(final Shape shape) {
                mBuilder.append("\tShape - " + shape.getShapeType() + ":\r\n");
                mBuilder.append("\t\tWidth: " + shape.getWidth() + "\r\n");
                mBuilder.append("\t\tHeight: " + shape.getHeight() + "\r\n");
                mBuilder.append("\t\tStroke color: " + shape.getStroke().getColor() + "\r\n");
                mBuilder.append("\t\tFill color: " + shape.getFill().getColor() + "\r\n");
                return VisitorAction.CONTINUE;
            }
        
            public int visitShapeEnd(final Shape shape) {
                mBuilder.append("\tEnd of shape\r\n");
                return VisitorAction.CONTINUE;
            }
        
            private StringBuilder mBuilder;
        }
      • visitSmartTagEnd

        public int visitSmartTagEnd(SmartTag smartTag)
                            throws java.lang.Exception
        Called when enumeration of a smart tag has ended.
        Parameters:
        smartTag - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every smart tag in a document.
        public void smartTagToText() throws Exception {
            Document doc = new Document(getMyDir() + "Smart tags.doc");
            SmartTagStructurePrinter visitor = new SmartTagStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
            testSmartTagToText(visitor); //ExEnd
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered SmartTag nodes and their children.
        /// </summary>
        public static class SmartTagStructurePrinter extends DocumentVisitor {
            public SmartTagStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideSmartTag = false;
            }
        
            /// <summary>
            /// Gets the plain text of the document that was accumulated by the visitor.
            /// </summary>
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideSmartTag) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SmartTag node is encountered in the document.
            /// </summary>
            public int visitSmartTagStart(final SmartTag smartTag) {
                indentAndAppendLine("[SmartTag start] Name: " + smartTag.getElement());
                mDocTraversalDepth++;
                mVisitorIsInsideSmartTag = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a SmartTag node have been visited.
            /// </summary>
            public int visitSmartTagEnd(final SmartTag smartTag) {
                mDocTraversalDepth--;
                indentAndAppendLine("[SmartTag end]");
                mVisitorIsInsideSmartTag = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideSmartTag;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitSmartTagStart

        public int visitSmartTagStart(SmartTag smartTag)
                              throws java.lang.Exception
        Called when enumeration of a smart tag has started.
        Parameters:
        smartTag - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every smart tag in a document.
        public void smartTagToText() throws Exception {
            Document doc = new Document(getMyDir() + "Smart tags.doc");
            SmartTagStructurePrinter visitor = new SmartTagStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
            testSmartTagToText(visitor); //ExEnd
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered SmartTag nodes and their children.
        /// </summary>
        public static class SmartTagStructurePrinter extends DocumentVisitor {
            public SmartTagStructurePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideSmartTag = false;
            }
        
            /// <summary>
            /// Gets the plain text of the document that was accumulated by the visitor.
            /// </summary>
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideSmartTag) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SmartTag node is encountered in the document.
            /// </summary>
            public int visitSmartTagStart(final SmartTag smartTag) {
                indentAndAppendLine("[SmartTag start] Name: " + smartTag.getElement());
                mDocTraversalDepth++;
                mVisitorIsInsideSmartTag = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a SmartTag node have been visited.
            /// </summary>
            public int visitSmartTagEnd(final SmartTag smartTag) {
                mDocTraversalDepth--;
                indentAndAppendLine("[SmartTag end]");
                mVisitorIsInsideSmartTag = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideSmartTag;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitSpecialChar

        public int visitSpecialChar(SpecialChar specialChar)
                            throws java.lang.Exception
        Called when a SpecialChar node is encountered in the document. This method is not be called for generic control characters (see ControlChar) that can be present in the document.
        Parameters:
        specialChar - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Implements the Visitor Pattern to remove all content formatted as hidden from the document.
        public void removeHiddenContentFromDocument() throws Exception {
            // Open the document we want to remove hidden content from
            Document doc = new Document(getMyDir() + "Hidden content.docx");
        
            // Create an object that inherits from the DocumentVisitor class
            RemoveHiddenContentVisitor hiddenContentRemover = new RemoveHiddenContentVisitor();
        
            // This is the well known Visitor pattern. Get the model to accept a visitor
            // The model will iterate through itself by calling the corresponding methods
            // on the visitor object (this is called visiting)
        
            // We can run it over the entire the document like so
            doc.accept(hiddenContentRemover);
        
            // Or we can run it on only a specific node
            Paragraph para = (Paragraph) doc.getChild(NodeType.PARAGRAPH, 4, true);
            para.accept(hiddenContentRemover);
        
            // Or over a different type of node like below
            Table table = (Table) doc.getChild(NodeType.TABLE, 0, true);
            table.accept(hiddenContentRemover);
        
            doc.save(getArtifactsDir() + "Font.RemoveHiddenContentFromDocument.docx");
        }
        
        /**
         * This class when executed will remove all hidden content from the Document. Implemented as a Visitor.
         */
        private class RemoveHiddenContentVisitor extends DocumentVisitor {
            /**
             * Called when a FieldStart node is encountered in the document.
             */
            public int visitFieldStart(final FieldStart fieldStart) throws Exception {
                // If this node is hidden, then remove it
                if (fieldStart.getFont().getHidden()) {
                    fieldStart.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldEnd node is encountered in the document.
             */
            public int visitFieldEnd(final FieldEnd fieldEnd) throws Exception {
                if (fieldEnd.getFont().getHidden()) {
                    fieldEnd.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldSeparator node is encountered in the document.
             */
            public int visitFieldSeparator(final FieldSeparator fieldSeparator) throws Exception {
                if (fieldSeparator.getFont().getHidden()) {
                    fieldSeparator.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Run node is encountered in the document.
             */
            public int visitRun(final Run run) throws Exception {
                if (run.getFont().getHidden()) {
                    run.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Paragraph node is encountered in the document.
             */
            public int visitParagraphStart(final Paragraph paragraph) throws Exception {
                if (paragraph.getParagraphBreakFont().getHidden()) {
                    paragraph.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FormField is encountered in the document.
             */
            public int visitFormField(final FormField field) throws Exception {
                if (field.getFont().getHidden()) {
                    field.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a GroupShape is encountered in the document.
             */
            public int visitGroupShapeStart(final GroupShape groupShape) throws Exception {
                if (groupShape.getFont().getHidden()) {
                    groupShape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Shape is encountered in the document.
             */
            public int visitShapeStart(final Shape shape) throws Exception {
                if (shape.getFont().getHidden()) {
                    shape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Comment is encountered in the document.
             */
            public int visitCommentStart(final Comment comment) throws Exception {
                if (comment.getFont().getHidden()) {
                    comment.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Footnote is encountered in the document.
             */
            public int visitFootnoteStart(final Footnote footnote) throws Exception {
                if (footnote.getFont().getHidden()) {
                    footnote.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SpecialCharacter is encountered in the document.
            /// </summary>
            public /*override*/ /*VisitorAction*/int visitSpecialChar(SpecialChar specialChar) {
                if (specialChar.getFont().getHidden())
                    specialChar.remove();
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Table node is ended in the document.
             */
            public int visitTableEnd(final Table table) {
                // At the moment there is no way to tell if a particular Table/Row/Cell is hidden.
                // Instead, if the content of a table is hidden, then all inline child nodes of the table should be
                // hidden and thus removed by previous visits as well. This will result in the container being empty
                // so if this is the case we know to remove the table node.
                //
                // Note that a table which is not hidden but simply has no content will not be affected by this algorithm,
                // as technically they are not completely empty (for example a properly formed Cell will have at least 
                // an empty paragraph in it)
                if (!table.hasChildNodes()) {
                    table.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Cell node is ended in the document.
             */
            public int visitCellEnd(final Cell cell) {
                if (!cell.hasChildNodes() && cell.getParentNode() != null) {
                    cell.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Row node is ended in the document.
             */
            public int visitRowEnd(final Row row) {
                if (!row.hasChildNodes() && row.getParentNode() != null) {
                    row.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
      • visitStructuredDocumentTagEnd

        public int visitStructuredDocumentTagEnd(StructuredDocumentTag sdt)
                                         throws java.lang.Exception
        Called when enumeration of a structured document tag has ended.
        Parameters:
        sdt - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every structured document tag in a document.
        public void structuredDocumentTagToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            StructuredDocumentTagNodePrinter visitor = new StructuredDocumentTagNodePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered StructuredDocumentTag nodes and their children.
        /// </summary>
        public static class StructuredDocumentTagNodePrinter extends DocumentVisitor {
            public StructuredDocumentTagNodePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideStructuredDocumentTag = false;
            }
        
            /// <summary>
            /// Gets the plain text of the document that was accumulated by the visitor.
            /// </summary>
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideStructuredDocumentTag) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a StructuredDocumentTag node is encountered in the document.
            /// </summary>
            public int visitStructuredDocumentTagStart(final StructuredDocumentTag sdt) {
                indentAndAppendLine("[StructuredDocumentTag start] Title: " + sdt.getTitle());
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a StructuredDocumentTag node have been visited.
            /// </summary>
            public int visitStructuredDocumentTagEnd(final StructuredDocumentTag sdt) {
                mDocTraversalDepth--;
                indentAndAppendLine("[StructuredDocumentTag end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideStructuredDocumentTag;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitStructuredDocumentTagRangeEnd

        public int visitStructuredDocumentTagRangeEnd(StructuredDocumentTagRangeEnd sdtRangeEnd)
                                              throws java.lang.Exception
      • visitStructuredDocumentTagRangeStart

        public int visitStructuredDocumentTagRangeStart(StructuredDocumentTagRangeStart sdtRangeStart)
                                                throws java.lang.Exception
      • visitStructuredDocumentTagStart

        public int visitStructuredDocumentTagStart(StructuredDocumentTag sdt)
                                           throws java.lang.Exception
        Called when enumeration of a structured document tag has started.
        Parameters:
        sdt - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every structured document tag in a document.
        public void structuredDocumentTagToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            StructuredDocumentTagNodePrinter visitor = new StructuredDocumentTagNodePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered StructuredDocumentTag nodes and their children.
        /// </summary>
        public static class StructuredDocumentTagNodePrinter extends DocumentVisitor {
            public StructuredDocumentTagNodePrinter() {
                mBuilder = new StringBuilder();
                mVisitorIsInsideStructuredDocumentTag = false;
            }
        
            /// <summary>
            /// Gets the plain text of the document that was accumulated by the visitor.
            /// </summary>
            public String getText() {
                return mBuilder.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                if (mVisitorIsInsideStructuredDocumentTag) {
                    indentAndAppendLine("[Run] \"" + run.getText() + "\"");
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a StructuredDocumentTag node is encountered in the document.
            /// </summary>
            public int visitStructuredDocumentTagStart(final StructuredDocumentTag sdt) {
                indentAndAppendLine("[StructuredDocumentTag start] Title: " + sdt.getTitle());
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a StructuredDocumentTag node have been visited.
            /// </summary>
            public int visitStructuredDocumentTagEnd(final StructuredDocumentTag sdt) {
                mDocTraversalDepth--;
                indentAndAppendLine("[StructuredDocumentTag end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mBuilder.append("|  ");
                }
        
                mBuilder.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideStructuredDocumentTag;
            private int mDocTraversalDepth;
            private StringBuilder mBuilder;
        }
      • visitSubDocument

        public int visitSubDocument(SubDocument subDocument)
                            throws java.lang.Exception
        Called when a subDocument is encountered.
        Parameters:
        subDocument - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to use a document visitor to print a document's node structure.
        public void docStructureToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            DocStructurePrinter visitor = new DocStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's tree of child nodes, and creates a map of this tree in the form of a string.
        /// </summary>
        public static class DocStructurePrinter extends DocumentVisitor {
            public DocStructurePrinter() {
                mAcceptingNodeChildTree = new StringBuilder();
            }
        
            public String getText() {
                return mAcceptingNodeChildTree.toString();
            }
        
            /// <summary>
            /// Called when a Document node is encountered.
            /// </summary>
            public int visitDocumentStart(Document doc) {
                int childNodeCount = doc.getChildNodes(NodeType.ANY, true).getCount();
        
                indentAndAppendLine("[Document start] Child nodes: " + childNodeCount);
                mDocTraversalDepth++;
        
                // Allow the visitor to continue visiting other nodes.
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Document node have been visited.
            /// </summary>
            public int visitDocumentEnd(Document doc) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Document end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Section node is encountered in the document.
            /// </summary>
            public int visitSectionStart(final Section section) {
                // Get the index of our section within the document
                NodeCollection docSections = section.getDocument().getChildNodes(NodeType.SECTION, false);
                int sectionIndex = docSections.indexOf(section);
        
                indentAndAppendLine("[Section start] Section index: " + sectionIndex);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Section node have been visited.
            /// </summary>
            public int visitSectionEnd(final Section section) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Section end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Body node is encountered in the document.
            /// </summary>
            public int visitBodyStart(final Body body) {
                int paragraphCount = body.getParagraphs().getCount();
                indentAndAppendLine("[Body start] Paragraphs: " + paragraphCount);
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Body node have been visited.
            /// </summary>
            public int visitBodyEnd(final Body body) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Body end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Paragraph node is encountered in the document.
            /// </summary>
            public int visitParagraphStart(final Paragraph paragraph) {
                indentAndAppendLine("[Paragraph start]");
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Paragraph node have been visited.
            /// </summary>
            public int visitParagraphEnd(final Paragraph paragraph) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Paragraph end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// </summary>
            public int visitRun(final Run run) {
                indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SubDocument node is encountered in the document.
            /// </summary>
            public int visitSubDocument(final SubDocument subDocument) {
                indentAndAppendLine("[SubDocument]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder and indent it depending on how deep the visitor is into the document tree.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mAcceptingNodeChildTree.append("|  ");
                }
        
                mAcceptingNodeChildTree.append(text + "\r\n");
            }
        
            private int mDocTraversalDepth;
            private StringBuilder mAcceptingNodeChildTree;
        }
      • visitTableEnd

        public int visitTableEnd(Table table)
                         throws java.lang.Exception
        Called when enumeration of a table has ended.
        Parameters:
        table - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Implements the Visitor Pattern to remove all content formatted as hidden from the document.
        public void removeHiddenContentFromDocument() throws Exception {
            // Open the document we want to remove hidden content from
            Document doc = new Document(getMyDir() + "Hidden content.docx");
        
            // Create an object that inherits from the DocumentVisitor class
            RemoveHiddenContentVisitor hiddenContentRemover = new RemoveHiddenContentVisitor();
        
            // This is the well known Visitor pattern. Get the model to accept a visitor
            // The model will iterate through itself by calling the corresponding methods
            // on the visitor object (this is called visiting)
        
            // We can run it over the entire the document like so
            doc.accept(hiddenContentRemover);
        
            // Or we can run it on only a specific node
            Paragraph para = (Paragraph) doc.getChild(NodeType.PARAGRAPH, 4, true);
            para.accept(hiddenContentRemover);
        
            // Or over a different type of node like below
            Table table = (Table) doc.getChild(NodeType.TABLE, 0, true);
            table.accept(hiddenContentRemover);
        
            doc.save(getArtifactsDir() + "Font.RemoveHiddenContentFromDocument.docx");
        }
        
        /**
         * This class when executed will remove all hidden content from the Document. Implemented as a Visitor.
         */
        private class RemoveHiddenContentVisitor extends DocumentVisitor {
            /**
             * Called when a FieldStart node is encountered in the document.
             */
            public int visitFieldStart(final FieldStart fieldStart) throws Exception {
                // If this node is hidden, then remove it
                if (fieldStart.getFont().getHidden()) {
                    fieldStart.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldEnd node is encountered in the document.
             */
            public int visitFieldEnd(final FieldEnd fieldEnd) throws Exception {
                if (fieldEnd.getFont().getHidden()) {
                    fieldEnd.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FieldSeparator node is encountered in the document.
             */
            public int visitFieldSeparator(final FieldSeparator fieldSeparator) throws Exception {
                if (fieldSeparator.getFont().getHidden()) {
                    fieldSeparator.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Run node is encountered in the document.
             */
            public int visitRun(final Run run) throws Exception {
                if (run.getFont().getHidden()) {
                    run.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Paragraph node is encountered in the document.
             */
            public int visitParagraphStart(final Paragraph paragraph) throws Exception {
                if (paragraph.getParagraphBreakFont().getHidden()) {
                    paragraph.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a FormField is encountered in the document.
             */
            public int visitFormField(final FormField field) throws Exception {
                if (field.getFont().getHidden()) {
                    field.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a GroupShape is encountered in the document.
             */
            public int visitGroupShapeStart(final GroupShape groupShape) throws Exception {
                if (groupShape.getFont().getHidden()) {
                    groupShape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Shape is encountered in the document.
             */
            public int visitShapeStart(final Shape shape) throws Exception {
                if (shape.getFont().getHidden()) {
                    shape.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Comment is encountered in the document.
             */
            public int visitCommentStart(final Comment comment) throws Exception {
                if (comment.getFont().getHidden()) {
                    comment.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when a Footnote is encountered in the document.
             */
            public int visitFootnoteStart(final Footnote footnote) throws Exception {
                if (footnote.getFont().getHidden()) {
                    footnote.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a SpecialCharacter is encountered in the document.
            /// </summary>
            public /*override*/ /*VisitorAction*/int visitSpecialChar(SpecialChar specialChar) {
                if (specialChar.getFont().getHidden())
                    specialChar.remove();
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Table node is ended in the document.
             */
            public int visitTableEnd(final Table table) {
                // At the moment there is no way to tell if a particular Table/Row/Cell is hidden.
                // Instead, if the content of a table is hidden, then all inline child nodes of the table should be
                // hidden and thus removed by previous visits as well. This will result in the container being empty
                // so if this is the case we know to remove the table node.
                //
                // Note that a table which is not hidden but simply has no content will not be affected by this algorithm,
                // as technically they are not completely empty (for example a properly formed Cell will have at least 
                // an empty paragraph in it)
                if (!table.hasChildNodes()) {
                    table.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Cell node is ended in the document.
             */
            public int visitCellEnd(final Cell cell) {
                if (!cell.hasChildNodes() && cell.getParentNode() != null) {
                    cell.remove();
                }
        
                return VisitorAction.CONTINUE;
            }
        
            /**
             * Called when visiting of a Row node is ended in the document.
             */
            public int visitRowEnd(final Row row) {
                if (!row.hasChildNodes() && row.getParentNode() != null) {
                    row.remove();
                }
        
                return VisitorAction.CONTINUE;
            }

        Example:

        Shows how to print the node structure of every table in a document.
        public void tableToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            TableStructurePrinter visitor = new TableStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered Table nodes and their children.
        /// </summary>
        public static class TableStructurePrinter extends DocumentVisitor {
            public TableStructurePrinter() {
                mVisitedTables = new StringBuilder();
                mVisitorIsInsideTable = false;
            }
        
            public String getText() {
                return mVisitedTables.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// Runs that are not within tables are not recorded.
            /// </summary>
            public /*override*/ /*VisitorAction*/int visitRun(Run run) {
                if (mVisitorIsInsideTable) indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Table is encountered in the document.
            /// </summary>
            public int visitTableStart(final Table table) {
                int rows = 0;
                int columns = 0;
        
                if (table.getRows().getCount() > 0) {
                    rows = table.getRows().getCount();
                    columns = table.getFirstRow().getCount();
                }
        
                indentAndAppendLine("[Table start] Size: " + rows + "x" + columns);
                mDocTraversalDepth++;
                mVisitorIsInsideTable = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Table node have been visited.
            /// </summary>
            public int visitTableEnd(final Table table) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Table end]");
                mVisitorIsInsideTable = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Row node is encountered in the document.
            /// </summary>
            public int visitRowStart(final Row row) {
                String rowContents = row.getText().replaceAll("\\u0007", ", ").replaceAll(", , ", "");
                int rowWidth = row.indexOf(row.getLastCell()) + 1;
                int rowIndex = row.getParentTable().indexOf(row);
                String rowStatusInTable = row.isFirstRow() && row.isLastRow() ? "only" : row.isFirstRow() ? "first" : row.isLastRow() ? "last" : "";
                if (!"".equals(rowStatusInTable)) {
                    rowStatusInTable = MessageFormat.format(", the {0} row in this table,", rowStatusInTable);
                }
        
                indentAndAppendLine(MessageFormat.format("[Row start] Row #{0}{1} width {2}, \"{3}\"", ++rowIndex, rowStatusInTable, rowWidth, rowContents));
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Row node have been visited.
            /// </summary>
            public int visitRowEnd(final Row row) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Row end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Cell node is encountered in the document.
            /// </summary>
            public int visitCellStart(final Cell cell) {
                Row row = cell.getParentRow();
                Table table = row.getParentTable();
                String cellStatusInRow = cell.isFirstCell() && cell.isLastCell() ? "only" : cell.isFirstCell() ? "first" : cell.isLastCell() ? "last" : "";
                if (!"".equals(cellStatusInRow)) {
                    cellStatusInRow = MessageFormat.format(", the {0} cell in this row", cellStatusInRow);
                }
        
                indentAndAppendLine(MessageFormat.format("[Cell start] Row {0}, Col {1}{2}", table.indexOf(row) + 1, row.indexOf(cell) + 1, cellStatusInRow));
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Cell node have been visited.
            /// </summary>
            public int visitCellEnd(final Cell cell) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Cell end]");
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder, and indent it depending on how deep the visitor is
            /// into the current table's tree of child nodes.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mVisitedTables.append("|  ");
                }
        
                mVisitedTables.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideTable;
            private int mDocTraversalDepth;
            private /*final*/ StringBuilder mVisitedTables;
        }
      • visitTableStart

        public int visitTableStart(Table table)
                           throws java.lang.Exception
        Called when enumeration of a table has started.
        Parameters:
        table - The object that is being visited.
        Returns:
        A VisitorAction value that specifies how to continue the enumeration.

        Example:

        Shows how to print the node structure of every table in a document.
        public void tableToText() throws Exception {
            Document doc = new Document(getMyDir() + "DocumentVisitor-compatible features.docx");
            TableStructurePrinter visitor = new TableStructurePrinter();
        
            // When we get a composite node to accept a document visitor, the visitor visits the accepting node,
            // and then traverses all of the node's children in a depth-first manner.
            // The visitor can read and modify each visited node.
            doc.accept(visitor);
        
            System.out.println(visitor.getText());
        }
        
        /// <summary>
        /// Traverses a node's non-binary tree of child nodes.
        /// Creates a map in the form of a string of all encountered Table nodes and their children.
        /// </summary>
        public static class TableStructurePrinter extends DocumentVisitor {
            public TableStructurePrinter() {
                mVisitedTables = new StringBuilder();
                mVisitorIsInsideTable = false;
            }
        
            public String getText() {
                return mVisitedTables.toString();
            }
        
            /// <summary>
            /// Called when a Run node is encountered in the document.
            /// Runs that are not within tables are not recorded.
            /// </summary>
            public /*override*/ /*VisitorAction*/int visitRun(Run run) {
                if (mVisitorIsInsideTable) indentAndAppendLine("[Run] \"" + run.getText() + "\"");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Table is encountered in the document.
            /// </summary>
            public int visitTableStart(final Table table) {
                int rows = 0;
                int columns = 0;
        
                if (table.getRows().getCount() > 0) {
                    rows = table.getRows().getCount();
                    columns = table.getFirstRow().getCount();
                }
        
                indentAndAppendLine("[Table start] Size: " + rows + "x" + columns);
                mDocTraversalDepth++;
                mVisitorIsInsideTable = true;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Table node have been visited.
            /// </summary>
            public int visitTableEnd(final Table table) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Table end]");
                mVisitorIsInsideTable = false;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Row node is encountered in the document.
            /// </summary>
            public int visitRowStart(final Row row) {
                String rowContents = row.getText().replaceAll("\\u0007", ", ").replaceAll(", , ", "");
                int rowWidth = row.indexOf(row.getLastCell()) + 1;
                int rowIndex = row.getParentTable().indexOf(row);
                String rowStatusInTable = row.isFirstRow() && row.isLastRow() ? "only" : row.isFirstRow() ? "first" : row.isLastRow() ? "last" : "";
                if (!"".equals(rowStatusInTable)) {
                    rowStatusInTable = MessageFormat.format(", the {0} row in this table,", rowStatusInTable);
                }
        
                indentAndAppendLine(MessageFormat.format("[Row start] Row #{0}{1} width {2}, \"{3}\"", ++rowIndex, rowStatusInTable, rowWidth, rowContents));
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Row node have been visited.
            /// </summary>
            public int visitRowEnd(final Row row) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Row end]");
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called when a Cell node is encountered in the document.
            /// </summary>
            public int visitCellStart(final Cell cell) {
                Row row = cell.getParentRow();
                Table table = row.getParentTable();
                String cellStatusInRow = cell.isFirstCell() && cell.isLastCell() ? "only" : cell.isFirstCell() ? "first" : cell.isLastCell() ? "last" : "";
                if (!"".equals(cellStatusInRow)) {
                    cellStatusInRow = MessageFormat.format(", the {0} cell in this row", cellStatusInRow);
                }
        
                indentAndAppendLine(MessageFormat.format("[Cell start] Row {0}, Col {1}{2}", table.indexOf(row) + 1, row.indexOf(cell) + 1, cellStatusInRow));
                mDocTraversalDepth++;
        
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Called after all the child nodes of a Cell node have been visited.
            /// </summary>
            public int visitCellEnd(final Cell cell) {
                mDocTraversalDepth--;
                indentAndAppendLine("[Cell end]");
                return VisitorAction.CONTINUE;
            }
        
            /// <summary>
            /// Append a line to the StringBuilder, and indent it depending on how deep the visitor is
            /// into the current table's tree of child nodes.
            /// </summary>
            /// <param name="text"></param>
            private void indentAndAppendLine(final String text) {
                for (int i = 0; i < mDocTraversalDepth; i++) {
                    mVisitedTables.append("|  ");
                }
        
                mVisitedTables.append(text + "\r\n");
            }
        
            private boolean mVisitorIsInsideTable;
            private int mDocTraversalDepth;
            private /*final*/ StringBuilder mVisitedTables;
        }