First bullet removed during ImportNode. Merging of two documents

I am having a problem with moving the contents of one document to a final document.
The problem I am experiencing is when the source document has bullets at the very beginning of the file.
Attached are the two documents.

Here is my code to do the insert of one doc into the other.

Document srcDoc = new Document("Bullet.doc");
Document destDoc = new Document("DestDoc.doc");

Node currentPosition = destDoc.Range.Bookmarks["AgenSum_TEXTAREA_CS"].BookmarkStart;

if (srcDoc.Sections.Count = 1)
{
    // If there is only one section in the rendered component, insert the section's contents
    // immediately after the bookmark
    InsertNodes(currentPosition, srcDoc.FirstSection);
}
public static void InsertNodes(Node currentPosition, Section renderedSection)
{
    // Add the rendered section after the bookmark
    BookmarkStart bs = (BookmarkStart)currentPosition;
    BookmarkEnd be = (BookmarkEnd)bs.Bookmark.BookmarkEnd;
    NodeCollection existingNodes = be.ParentNode.ParentNode.ChildNodes;
    Node lastInsertedParagraph = null;
    int index = existingNodes.IndexOf(be.ParentNode);

    // If there is more than one paragraph to import and if the paragraph where we will be inserting
    // has any (residual) children after the bookmark end, then those residual children will have
    // to be added as siblings at the end of the childnode collection of the last imported paragraph.
    List residuals = new List();
    NodeCollection childrenToImport = renderedSection.Body.ChildNodes;
    int totChildrenToImport = childrenToImport.Count;
    int indexOfBe = be.ParentNode.IndexOf(be);
    int indexOfSiblingAfterBe = indexOfBe + 1;
    int totBeSiblings = be.ParentNode.ChildNodes.Count;
    if (totChildrenToImport > 1 && totBeSiblings > 1 && indexOfSiblingAfterBe < totBeSiblings)
    {
        // Collect the residual children
        for (int i = indexOfSiblingAfterBe; i < totBeSiblings; i++)
        {
            residuals.Add(be.ParentNode.ChildNodes[i]);
        }
        // Remove the residuals from the template
        foreach (Node node in residuals)
        {
            be.ParentNode.ChildNodes.Remove(node);
        }
    }
    Aspose.Words.Paragraph paraOfBookmarkEnd = null;

    foreach (Node sourceNode in renderedSection.Body.ChildNodes)
    {
        // Only Aspose.Words.Paragraph or Table nodes can be inserted into Cell or Shape
        if (sourceNode.NodeType == NodeType.Paragraph || sourceNode.NodeType == NodeType.Table)
        {
            // Do not insert node if it is a last empty paragraph in the section.
            if (sourceNode.NodeType == NodeType.Paragraph && sourceNode == renderedSection.Body.LastChild && sourceNode.GetText() == string.Empty)
                break;
            // if the node is the first node, add its children to the existing paragraph
            if (sourceNode == renderedSection.Body.FirstChild)
            {
                if (sourceNode.NodeType == NodeType.Paragraph)
                {
                    paraOfBookmarkEnd = (Aspose.Words.Paragraph)existingNodes[index];
                    int beIndex = paraOfBookmarkEnd.IndexOf(be);
                    foreach (Node run in ((CompositeNode)sourceNode))
                    {
                        if (run.NodeType == NodeType.Shape)
                        {
                            //// If we're dealing with a Shape, assume its an embedded grid and set the paragraphs
                            //// right indent to the far right. This should keep the paragraph from creating an unwanted line.
                            Aspose.Words.Paragraph paraOfBookmarkStart = (Aspose.Words.Paragraph)bs.GetAncestor(NodeType.Paragraph);
                            if (paraOfBookmarkStart.ParagraphFormat.Alignment != ParagraphAlignment.Center)
                            {
                                // Only if not center aligned (otherwise will offset from center)
                                PageSetup setup = ((Section)be.GetAncestor(NodeType.Section)).PageSetup;
                                paraOfBookmarkStart.ParagraphFormat.RightIndent = -setup.RightMargin;
                            }
                        }
                        Node insertedNode = currentPosition.Document.ImportNode(run, true, ImportFormatMode.UseDestinationStyles);
                        paraOfBookmarkEnd.ChildNodes.Insert(++beIndex, insertedNode);
                    }
                }
                else
                {
                    // Here we assume its a Table
                    lastInsertedParagraph = currentPosition.Document.ImportNode(sourceNode, true, ImportFormatMode.UseDestinationStyles);
                    existingNodes.Insert(++index, lastInsertedParagraph);
                }
            }
            else
            {
                lastInsertedParagraph = currentPosition.Document.ImportNode(sourceNode, true, ImportFormatMode.UseDestinationStyles);

                // TODO: Do we need this for OSD? If it breaks Army/AF may want to try removing it.
                if (sourceNode.NodeType == NodeType.Paragraph) //Only do CopyFont if is paragraph
                {
                    if (paraOfBookmarkEnd != null)
                    {
                        ((Aspose.Words.Paragraph)lastInsertedParagraph).ParagraphFormat.Style = paraOfBookmarkEnd.ParagraphFormat.Style;
                    }
                }

                existingNodes.Insert(++index, lastInsertedParagraph);
            }
        }
    }

    // Add back the residuals
    if (residuals.Count > 0)
    {
        foreach (Node run in residuals)
        {
            // Always keep the source formatting when adding back the residuals
            Node insertedRun = currentPosition.Document.ImportNode(run, true, ImportFormatMode.KeepSourceFormatting);
            ((CompositeNode)lastInsertedParagraph).ChildNodes.Insert(++index, insertedRun);
        }
    }
}

then I call this method to remove the book mark.

RemoveBookmark(currentPosition, "AgenSum_TEXTAREA_CS")
private void RemoveBookmark(Node currentPosition, string bookMark)
{
    Table newTable = null;
    DocumentBuilder docBuilder = new DocumentBuilder(_template);
    BookmarkStart bs = (BookmarkStart)currentPosition;
    docBuilder.MoveToBookmark(bs.Bookmark.Name);

    // If a table was the first thing added to the rendered component, get a reference to the table
    // that was merged into the template.
    if ((AsposeUtil.IsEmptyParagraph(_renderedComponent.FirstSection.Body.FirstChild) &&
    _renderedComponent.Sections.Count > 1 &&
    _renderedComponent.Sections[1].Body.FirstChild.NodeType == NodeType.Table))
    {
        if (docBuilder.CurrentNode.ParentNode.NextSibling.NextSibling != null &&
        docBuilder.CurrentNode.ParentNode.NextSibling.NextSibling.NodeType == NodeType.Table)
        {
            newTable = (Table)docBuilder.CurrentNode.ParentNode.NextSibling.NextSibling;
        }
        else if (docBuilder.CurrentNode.ParentNode.NextSibling != null &&
        docBuilder.CurrentNode.ParentNode.NextSibling.NodeType == NodeType.Table)
        {
            newTable = (Table)docBuilder.CurrentNode.ParentNode.NextSibling;
        }
    }
    else if (_renderedComponent.FirstSection.Body.FirstChild.NodeType == NodeType.Table)
    {
        newTable = (Table)docBuilder.CurrentNode.ParentNode.NextSibling.NextSibling;
    }

    // Remove the bookmark we just processed.
    Bookmark bookmark = _template.Range.Bookmarks[bookMark];
    bookmark.Text = "";
    bookmark.Remove();

    if (newTable != null)
    {
        // If a table was the first thing added to the built component, we
        // must remove the paragraph break that preceeds the table. Normally
        // removing the bookmark will remove the embedded paragraph breaks but Aspose
        // leaves one if a table is added.
        if (newTable.PreviousSibling.NodeType == NodeType.Paragraph &&
        AsposeUtil.IsEmptyParagraph(newTable.PreviousSibling))
        {
            newTable.PreviousSibling.Remove();
        }
    }
}

After all this, the first bullet is removed but it’s text is still there, and only the second two bullets are shown as bullets. I think it has something to do with the fact that I am adding bullets on the same line as bookmark, but don’t understand why it happens or how to fix it. When I print document mid insertdoc, it see book mark and then the #1 next to it without the bullet, so I know it has nothing to do with the RemoveBookmark method.

Thanks for your help in advance.

Hi
Thanks for your request. Bullet is lost because you do not actually copy the first paragraph into the destination document. You copy only content of the first paragraph, but since bullet is an option of a paragraph, it is lost.
If you try using the code provided here to copy one document into another bullets will be preserved:
https://docs.aspose.com/words/java/insert-and-append-documents/
Best regards,

Thanks for the quick reply. I’ll try an adopt this new method, but I see a lot of similarities in my procedure. Does this importdocument method handle table, images and formatting without any problems? Will it literally take the source file and mirror it in the destination file, format and all?

Oh, and to be more clear, if I use KeepSource formatting in order to mirror the format from source to destination, will it only affect what is being added to destination and not affect the other content already in the destination file?

Hi
Thanks for your request. Yes, this method is similar to yours. The only difference is that content of the first paragraph of the source document is not copied into the paragraph in the destination document, but whole first paragraph is inserted after the paragraph in the destination document.
Sure, this method handles paragraphs, tables, images, etc.
Yes, when you use KeepSourceFormatting it will affect only content copied from the source document.
Best regards,

I was using version 9.4 when I implemented this fix initially. Does the new 10.3 version have an integrated Insert doc into another doc method yet? Or do I still have to use the method mentioned in your first reply?

Hi
Thanks for your request. No, 10.3version does not have builtin InsertDocument method. You should use the same method as I mentioned earlier.
Best regards,

Hello,

I have recently tried to implement this fix and I am seeing that the source document actually gets inserted inside the bookmark. I followed the following documentation:

https://docs.aspose.com/words/net/insert-and-append-documents/

I would like the bookmark to just be a location where the document gets added to but not actually keep the bookmark. Currently my code actually removes all the bookmarks once the document is generated, which means the text added from the source document is also removed. Can you please suggest an solution to my problem? We are now in version 10.5.

Thanks,
Daniel

Hi Daniel,

Thanks for your inquiry. I think, you can simply remove the bookmark once the document is inserted at its place e.g:

Document mainDoc = new Document(MyDir + "InsertDocument1.doc");
Document subDoc = new Document(MyDir + "InsertDocument2.doc");

Bookmark bookmark = mainDoc.Range.Bookmarks["insertionPlace"];
InsertDocument(bookmark.BookmarkStart.ParentNode, subDoc);

bookmark.Remove();

mainDoc.Save(MyDir + "InsertDocumentAtBookmark Out.doc");

In this case the text added from the second document will not be removed.

I hope, this will help.

Best Regards,

This is exactly what I am doing and it doesn’t work since it adds the document INSIDE the bookmark. For example, if I call the bookmark [BULLETS], then when the text is inserted into the template that has the bookmark the result is this:

[BULLETS

  • Bullet 1
  • Bullet 2
  • Bullet 3]

So then when I remove the bookmark, everything gets removed. Any ideas?

Hi Daniel,

Thanks for your inquiry While using Aspose.Words v11.0.0 (Latest version) and the code provided in this article, I was unable to reproduce this problem on my side. Could you please create and attach a simple console application along with two Word documents here for testing? I will investigate the issue further and provide you more information.

Best Regards,

I found the issue. It was the name I gave my bookmark. I had an extra space at the end like so: [BULLETS ]. Once I changed it to [BULLETS] it worked. Thanks for your help.

Hi,

Thanks for your feedback. It is perfect that you managed to resolve the problem on your side. If we can help you with anything else, please feel free to ask.

Best Regards,

Hello again, so I have found another issue with this method. Well, is probably not an issue, but doesn’t meet my needs. Let me paint a picture of what I want to do.
MAIN TEMPLATE
Heading Text: [BOOKMARK1]
Heading Text2:
[BOOKMARK2].
I want final generation to look like:
Heading Text: This text came from Document1
Heading Text2:
This text came from Document2
Currently is generation like this:
Heading Text:
This text came from Document1
Heading Text2:

This text came from Document2
I have determined that the text from the documents is being added after the bookmark’s paragraph (ParentNode), thus the extra line break before each text being inserted. I would like to literally insert the contents of the documents in the same paragraph/line as where the bookmarks are. We eventually remove the bookmarks, so we really just want to replace the bookmark with the contents of the document being merged from (src doc).
If the InsertDocument method only deals with paragraphs and since it appears two paragraphs can’t be in the same line, how can I achieve this desired outcome?
Thanks for you help in advance.
Daniel

Hi
Daniel,

Thanks for the additional information. First of all, please note that a minimal valid Word document needs to have at least one section and a minimal valid section needs to have a Body with one Paragraph. The line space after the Bookmark is appearing because of this Paragraph. This is entirely by design. Secondly, I think, in your case you need to extract all nodes from inside the document Body and import them into the main document manually. For this, you can write your own content exporter by using the DocumentVisitor class. I think the following article would be helpful to you:
https://docs.aspose.com/words/net/how-to-extract-selected-content-between-nodes-in-a-document/

If we can help you with anything else, please feel free to ask.

Best Regards,

Well, before I give this a try, will all the formatting of the text also be moved to the main document? This was the issue originally if you see my first post above. I need to be able to keep the bullet formatting if a bullet is what I am moving from one document to the other.
Thanks

Hi Daniel,

Thanks for your inquiry. I believe this is the base method you would use to achieve what you are looking for. Moreover, yes, you could then add in some calls to the Font classes to extract the formatting as well.

Best Regards,

Hi Daniel,

Thanks for your inquiry.

Although the suggestion made by Awais is correct, it may involve a bit more coding. I can offer another solution.

Please try using the code from the following thread: https://forum.aspose.com/t/58972

This will allow you to insert a document on the same line as the bookmark in the destination document. We will include this functionality into a method in the Aspose.Words API in a future version.

Thanks,

Hey Adam,
Thanks for this extra information. This sounds like is exactly what we need. However, I cannot see what’s in the link. It says that I don’t have permission for the requested action.
Thanks in advanced.
Daniel

Hi Daniel,

Thanks for your inquiry

I apologise, the code snippet is found inside a private thread. Please find the code below for your reference.

public static void InsertDocumentAtBookmark(String bookmarkName, Document dstDoc, DocumentsrcDoc)
{

    NodeImporter importer = new NodeImporter(srcDoc, dstDoc, ImportFormatMode.UseDestinationStyles);
    // Create DocumentBuilder
    DocumentBuilder builder = new DocumentBuilder(dstDoc);
    // Move cursor to bookmark and insert paragraph break
    builder.MoveToBookmark(bookmarkName);
    builder.Writeln();
    // If current paragraph is a list item, we should clear its formating.
    if (builder.CurrentParagraph.IsListItem)
        builder.ListFormat.RemoveNumbers();
    // Content of srcdoc will be inserted after this node
    Node insertAfterNode = builder.CurrentParagraph.PreviousSibling;
    // Content of first paragraph of srcDoc will be apended to this parafraph
    Paragraph insertAfterParagraph = null;
    if (insertAfterNode.NodeType == NodeType.Paragraph)
        insertAfterParagraph = (Paragraph)insertAfterNode;
    // Content of last paragraph of srcDoc will be apended to this parafraph
    Paragraph insertBeforeParagraph = builder.CurrentParagraph;
    // We will be inserting into the parent of the destination paragraph.
    CompositeNode dstStory = insertAfterNode.ParentNode;
    // Remove empty paragraphs from the end of document
    while (!((CompositeNode)srcDoc.LastSection.Body.LastChild).HasChildNodes)
    {
        srcDoc.LastSection.Body.LastParagraph.Remove();
        if (srcDoc.LastSection.Body.LastChild == null)
            break;
    }
    // Loop through all sections in the source document.

    foreach (Section srcSection in srcDoc.Sections)
    {
        // Loop through all block level nodes (paragraphs and tables) in the body of the section.
        for (int nodeIdx = 0; nodeIdx < srcSection.Body.ChildNodes.Count; nodeIdx++)
        {
            Node srcNode = srcSection.Body.ChildNodes[nodeIdx];
            // Do not insert node if it is a last empty paragarph in the section.
            Paragraph para = null;
            if (srcNode.NodeType == NodeType.Paragraph)
                para = (Paragraph)srcNode;

            if ((para != null) && para.IsEndOfSection && (!para.HasChildNodes))
                break;

            // If current paragraph is first paragraph of srcDoc
            // then appent its content to insertAfterParagraph
            bool nodeInserted = false;
            if (para != null && para.Equals(srcDoc.FirstSection.Body.FirstChild))
            {
                nodeInserted = true; // set this flag to know that we already processed this node.
                for (int i = 0; i < para.ChildNodes.Count; i++)
                {
                    Node node = para.ChildNodes[i];
                    Node dstNode = importer.ImportNode(node, true);
                    insertAfterParagraph.AppendChild(dstNode);
                }

                // If subdocument contains only one paragraph
                // then copy content of insertBeforeParagraph to insertAfterParagraph
                // and remove insertBeforeParagraph
                if (srcDoc.FirstSection.Body.FirstParagraph.Equals(srcDoc.LastSection.Body.LastChild))
                {
                    while (insertBeforeParagraph.HasChildNodes)
                        insertAfterParagraph.AppendChild(insertBeforeParagraph.FirstChild);

                    insertBeforeParagraph.Remove();
                }
            }
            // If current paragraph is last paragraph of srcDoc
            // then appent its content to insertBeforeParagraph
            if (para != null && para.Equals(srcDoc.LastSection.Body.LastChild))
            {
                nodeInserted = true; // set this flag to know that we already processed this node.
                Node previouseNode = null;
                for (int i = 0; i < para.ChildNodes.Count; i++)
                {
                    Node node = para.ChildNodes[i];
                    Node dstNode = importer.ImportNode(node, true);
                    if (previouseNode == null)
                        insertBeforeParagraph.InsertBefore(dstNode, insertBeforeParagraph.FirstChild);
                    else
                        insertBeforeParagraph.InsertAfter(dstNode, previouseNode);

                    previouseNode = dstNode;
                }
            }

            if (!nodeInserted)
            {
                // This creates a clone of the node, suitable for insertion into the destination document.
                Node newNode = importer.ImportNode(srcNode, true);
                // Insert new node after the reference node.
                dstStory.InsertAfter(newNode, insertAfterNode);
                insertAfterNode = newNode;
            }
        }
    }
}

Thanks,

Adam,
Thanks again for the information but I have just tried this fix and it does not work for me. First of all, if my src document starts with bullets, the first bullet gets its formatting stripped out. Secondly, it adds the contents INSIDE the bookmark, so when I remove the bookmark, it removes the text inserted from the source document. I need a method that will keep the formatting of all lines from the src document but drop it NEXT to where the bookmark is at so when I remove the bookmark the text pretty much replaces the bookmark.
Thanks,
Daniel