Moving Cursor to Bookmark End moves it out of the table

Hi,

Can you tell me how I can move DocumentBuilder cursor to the place where I have bookmark end located?

Please see the document attached. I open it and try to do the following.

        private void ReplaceBookmark(Bookmark bookmark, Document document)
    {
        var documentBuilder = new DocumentBuilder(document);
  
        documentBuilder.MoveTo(bookmark.BookmarkStart);
        documentBuilder.InsertField($"MERGEFIELD TableStart:{repeatingPartId}");
        documentBuilder.MoveTo(bookmark.BookmarkEnd);
        documentBuilder.InsertField($"MERGEFIELD TableEnd:{repeatingPartId}");
    }

What I observe is that the field I insert is placed not where the BookmarkEnd is located in the loaded document, but in the next cell. As a matter of fact It looks like it inserts the field in the next row or if the BookmarkEnd is in the last row, outside the table.

See the files attached, one before running the code and the other after changes.

Thanks,
LukaszBookmarkEnd.zip (18.4 KB)

@acturisaspose

Thanks for your inquiry. The BookmarkEnd is after the table’s row. You can find it in the document.xml of your document. Please check the attached image for detail. This is the reason the field is inserted in the next row.

To get the document.xml of your document, please change the extension of your document from .dot to .zip and exract the content of ZIP file.

Hi Tahir,

Thank you for explanation. Do you maybe know why it is like that? I would expect the bookmark to be in the cell, the same as it is rendered, i.e. in the the cell.

What I can also see now is that the “start” field is inserted in the first cell in the document. Why is it different? Bookmark start is located before the cell where it is rendered.

Additionally, can you tell me if I can and how I can move cursor back to the cell?

Thanks,
Lukasz

@acturisaspose

Thanks for your inquiry. The BookmarkEnd is inserted after the table’s row when you bookmark the entire row. You need to select the row’s text instead of the entire row when you insert the bookmark.

Following code example moves the BookmarkEnd node to the last paragraph of row. Please use the latest version of Aspose.Words for .NET 18.10.

Document document = new Document(MyDir + "Before.dot");

Bookmark bookmark= document.Range.Bookmarks["RatingNotes1"];
Console.WriteLine(bookmark.BookmarkEnd.PreviousSibling);

if (bookmark.BookmarkEnd.PreviousSibling.NodeType == NodeType.Row)
{
    ((Row)bookmark.BookmarkEnd.PreviousSibling).LastCell.LastParagraph.AppendChild(new BookmarkEnd(document, "RatingNotes1"));
    document.UpdatePageLayout();
}

var documentBuilder = new DocumentBuilder(document);

bookmark = document.Range.Bookmarks["RatingNotes1"];
documentBuilder.MoveTo(bookmark.BookmarkStart);
documentBuilder.InsertField("MERGEFIELD TableStart:{repeatingPartId}");
documentBuilder.MoveTo(bookmark.BookmarkEnd);
documentBuilder.InsertField("MERGEFIELD TableEnd:{repeatingPartId}");

document.Save(MyDir + "18.10.docx");

Hi Tahir,

Thank you for your prompt response and the example.

However, there are lots of documents I get and I would like to automate my work, so I do not have to manually go through each of them and change bookmarks.

Is there a way of moving back to the cell in cases where I have a bookmark around the entire row as in my document?

P.S. just out of curiosity, why the field is inserted in the cell when there is bookmark start?

Thank you,
Lukasz

@acturisaspose

Thanks for your inquiry.

You can achieve your requirement using Aspose.Words, as shown in the code example, shared in my previous post.

Please check the code example shared in my previous post. You need to check if the previous/next sibling of BookmarkStart/BookmarkEnd is Row, move the cursor to the first/last node of the cell.

Please read the following article.
Moving the Cursor

In your document, the BookmarkStart is inside table’s cell. However, BookmarkEnd node is outside the row. Could you please share some more detail about this query? We will then share more information on it.

Hi,

Thank you for your response and tips. I will need to investigate this on our side.

Thanks,
Lukasz

Hi Tahir,

Could you please tell me why I do not have any siblings for BookmarkEnd when I create Document object with theBookmarkEndNoSiblings.zip (8.6 KB)
attached document? When I open it, as in previous example I get null for PreviousSibling.

Thank you,
Lukasz

@acturisaspose

Thanks for your inquiry. Please use the following modified code example to get the desired output.

Document document = new Document(MyDir + "BookmarkEndNoSiblings.dot");

Bookmark bookmark = document.Range.Bookmarks["RatingNotes1"];
Console.WriteLine(bookmark.BookmarkEnd.PreviousSibling);

if (bookmark.BookmarkEnd.PreviousSibling != null && bookmark.BookmarkEnd.PreviousSibling.NodeType == NodeType.Row)
{
    ((Row)bookmark.BookmarkEnd.PreviousSibling).LastCell.LastParagraph.AppendChild(new BookmarkEnd(document, "RatingNotes1"));
    document.UpdatePageLayout();
}
else if (bookmark.BookmarkEnd.PreviousSibling == null)
{
    Node node = bookmark.BookmarkEnd.ParentNode.PreviousPreOrder(document);
    if (node != null && node.GetAncestor(NodeType.Row) != null)
    {
        Row row = (Row)node.GetAncestor(NodeType.Row);
        row.LastCell.LastParagraph.AppendChild(new BookmarkEnd(document, "RatingNotes1"));
    }
                     
}

document.Save(MyDir + "18.10.docx");

Hi Tahir,

Thank you for your prompt response and the code example. I have tried using it with both of the templates I provided “Before.dot” and “BookmarkEndNoSiblings.dot” however, for the first one now I am getting error that ParentNode cannot be null whenever I want to move to the newly created BookmarkEnd (am I right that the old BookmarkEnd is dereferenced from the bookmark itself?) and for the second one the field gets inserted right after the table.

Additionally I can see that the content (bookmark.Text) now contains the text that was previously wrapped in bookmark + the text that is outside of the table.

See the code example using your code example.

        private void SurroundBookmarkContentWithFields(Bookmark bookmark, Document document)
    {
        var documentBuilder = new DocumentBuilder(document);

        if (bookmark.BookmarkEnd.PreviousSibling != null && bookmark.BookmarkEnd.PreviousSibling.NodeType == NodeType.Row)
        {
            ((Row)bookmark.BookmarkEnd.PreviousSibling).LastCell.LastParagraph.AppendChild(new BookmarkEnd(document, bookmark.Name));
            document.UpdatePageLayout();
        }
        else if (bookmark.BookmarkEnd.PreviousSibling == null)
        {
            var node = bookmark.BookmarkEnd.ParentNode.PreviousPreOrder(document);
            if (node?.GetAncestor(NodeType.Row) != null)
            {
                var row = (Row)node.GetAncestor(NodeType.Row);
                row.LastCell.LastParagraph.AppendChild(new BookmarkEnd(document, bookmark.Name));
            }

        }

        documentBuilder.MoveTo(bookmark.BookmarkStart);
        documentBuilder.InsertField($"MERGEFIELD TableStart:{bookmark.Name}");
        documentBuilder.MoveTo(bookmark.BookmarkEnd);
        documentBuilder.InsertField($"MERGEFIELD TableEnd:{bookmark.Name}");
    }

Thank you,
Lukasz

@acturisaspose

Thanks for your inquiry. We have tested the scenario and have managed to reproduce the same issue at our side. For the sake of correction, we have logged this problem in our issue tracking system as WORDSNET-17564. You will be notified via this forum thread once this issue is resolved.

We apologize for your inconvenience.

Hi, this functionality is very important to us. Do you have any timescale, estimated fix date? If the fix cannot be delivered promptly, would you be able to think of any workaround?

@acturisaspose

Thanks for your inquiry. We try our best to deal with every customer request in a timely fashion, we unfortunately cannot guarantee a delivery date to every customer issue. We work on issues on a first come, first served basis. We feel this is the fairest and most appropriate way to satisfy the needs of the majority of our customers.

Currently, your issue is pending for analysis and is in the queue. Once we complete the analysis of your issue, we will then be able to provide you an estimate.

You reported this issue in free support forum and it will be treated with normal priority. To speed up the progress of issue’s resolution, we suggest you please check our paid support policies from following link.
Paid Support Policies

Hi Tahir,

Thank you for your response. I can see that the issue status has changed. Would you be able to provide an estimate?

Thank you,
Lukasz

@acturisaspose

Thanks for your inquiry. Unfortunately, there is no ETA available at the moment. We will inform you via this forum thread once there is an update available on this issue.

Thanks for your patience.

Hi Tahir,

Thank you for your response. I have been trying to find a workaround to the issue and used the code you provided to move cursor before the bookmark and do the insert documentBuilder.InsertField($"MERGEFIELD TableEnd:{bookmark.Name}"); but I have not been successful, as the node found by var node = bookmark.BookmarkEnd.ParentNode.PreviousPreOrder(document); it is not the cell before the bookmark.

Please see the code example below and the template bookmark Orig.zip (8.5 KB)
I am using attached. The template is 2x2 and has [row,column]. In Words xml as you stated above:

  • BookmarkStart is located in [1,1]
  • BookmarkEnd is located after [1,2]

But the code below var node = bookmark.BookmarkEnd.ParentNode.PreviousPreOrder(document); finds the second row not the first one, so when I do the insert, it is inserted in the second row and last cell. Can you tell me why?

        var documentBuilder = new DocumentBuilder(document);
        documentBuilder.MoveTo(bookmark.BookmarkStart);
        documentBuilder.InsertField($"MERGEFIELD TableStart:{repeatingPartId}");

        if (bookmark.BookmarkEnd.PreviousSibling != null && bookmark.BookmarkEnd.PreviousSibling.NodeType == NodeType.Row)
        {
            var row = (Row) bookmark.BookmarkEnd.PreviousSibling;
            documentBuilder.MoveTo(row.LastCell.LastParagraph);
            documentBuilder.InsertField($"MERGEFIELD TableEnd:{repeatingPartId}");
        }
        else if (bookmark.BookmarkEnd.PreviousSibling == null)
        {
            var node = bookmark.BookmarkEnd.ParentNode.PreviousPreOrder(document);
            if (node?.GetAncestor(NodeType.Row) != null)
            {
                var row = (Row)node.GetAncestor(NodeType.Row);
                documentBuilder.MoveTo(row.LastCell.LastParagraph);
                documentBuilder.InsertField($"MERGEFIELD TableEnd:{repeatingPartId}");
            }
        }
        else
        {
            documentBuilder.MoveTo(bookmark.BookmarkEnd);
            documentBuilder.InsertField($"MERGEFIELD TableEnd:{repeatingPartId}");
        }

thanks,
Lukasz

@acturisaspose

Thanks for your inquiry. Please use LoadOptions.AnnotationsAtBlockLevel property as shown below to avoid the shared exception. Hope this helps you.

Aspose.Words.LoadOptions options = new Aspose.Words.LoadOptions();
options.AnnotationsAtBlockLevel = false;
Document document = new Document(MyDir + "before.dot", options);

@acturisaspose

Thanks for your patience. It is to inform you that the issue which you are facing is actually not a bug in Aspose.Words. So, we have closed this issue (WORDSNET-17564) as ‘Not a Bug’.

The code example inserts the BookmarkEnd node before existing one with the same duplicate name. When Document.UpdatePageLayout method is called, it updates page layout. Aspose.Words verifies correctness of the document and removes the second (original) BookmarkEnd. So, moving to this BookmarkEnd throws an exception.

Please get the bookmark again after calling Document.UpdatePageLayout method to avoid the exception.

document.UpdatePageLayout();
//Get the bookmark again.
bookmark = document.Range.Bookmarks["RatingNotes1"];


documentBuilder.MoveTo(bookmark.BookmarkStart);
documentBuilder.InsertField($"MERGEFIELD TableStart:{bookmark.Name}");
documentBuilder.MoveTo(bookmark.BookmarkEnd);
documentBuilder.InsertField($"MERGEFIELD TableEnd:{bookmark.Name}");

Hi Tahir,

Thank you for update.

Lukasz

@acturisaspose

Please feel free to ask if you have any question about Aspose.Words, we will be happy to help you.