Object reference not set to an instance of an object error when inserting a table row


#21

Sorry, there seems to still be a misunderstanding, there will only ever be one row to add to a document (at least as far is as known at this time). To clarify:

  1. I need to add a single table row in one Word document into another table in another Word document.
  2. The Word document with the table with only one row will contain nothing else but that single table row and that row may or may not contain a content control.
  3. The Word document with the main table into which the row will be inserted will contain multiple tables (number and position unknown until runtime time), multiple bookmarks (number and position unknown until runtime time), multiple content controls (number and position unknown until runtime time) and plain text in varying formats.
  4. The main table will be uniquely identified by 3 attributes that will not be known at design time and so must be generic: (a) table title property, (b) which bookmark it comes after, (c ) preceding text (which may or may not be immediately before the table).
  5. I need to find the first table found matching the specified (a) and (b) that comes after the specified search text (c ).
  6. I will not know how many rows the main table to be inserted into will have prior to editing, but the single row needs to be added to the bottom of it.

Whilst all of the above have been achieved within my code, I do not know how to amalgamate all 3 requirements (i.e. all 3 parameters tableTitle, bookmarkName, searchText). And your suggestion is not generic as the indexes for the table/row are hardcoded and I will not be finding the tables by index and nor will I know how many rows there are.

I hope this has made the problem clear but let me know if you have any further questions?


#22

@SCDGLC,

Thanks for the additional information. We are checking this scenario further on our end and will get back to you soon.


#23

Much appreciated, thank you.


#24

Hi, just wondering how you’re getting on and if you’ve found any way to accomplish this yet?


#25

@SCDGLC,

Please see the following sample input/output Word documents:

Docs.zip (76.6 KB)

In the “ERROR_Table1.docx” document, I have inserted a couple more Tables with title “Strawberry Delight” under “Bookmark2” and a “Search Text” in between them.

The following code appends Row to the first Table under specified Bookmark after “Search Text”.

InsertTableRow(@"E:\temp\ERROR_RowTest\Error_row.docx",
                @"E:\temp\ERROR_RowTest\\Error_table1.docx",
                @"E:\temp\ERROR_RowTest\\19.10.docx",
                "Bookmark2",
                "Strawberry Delight",
                "Search Text");

private class FindAndReplace : IReplacingCallback
{
    public object BookmarkName { get; internal set; }
    public string TableTitle { get; internal set; }
    public string SearchText { get; internal set; }
    public Table TheTable { get; set; }

    ReplaceAction IReplacingCallback.Replacing(ReplacingArgs e)
    {
        // This is a Run node that contains either the beginning or the complete match.
        Node currentNode = e.MatchNode;

        // The first (and may be the only) run can contain text before the match,
        // in this case it is necessary to split the run.
        if (e.MatchOffset > 0)
            currentNode = SplitRun((Run)currentNode, e.MatchOffset);

        // This array is used to store all nodes of the match for further removing.
        ArrayList runs = new ArrayList();

        // Find all runs that contain parts of the match string.
        int remainingLength = e.Match.Value.Length;

        while ((remainingLength > 0) &&
            (currentNode != null) &&
            (currentNode.GetText().Length <= remainingLength))
        {
            runs.Add(currentNode);
            remainingLength = remainingLength - currentNode.GetText().Length;

            // Select the next Run node.
            // Have to loop because there could be other nodes such as BookmarkStart etc.
            do
            {
                currentNode = currentNode.NextSibling;
            }
            while ((currentNode != null) && (currentNode.NodeType != NodeType.Run));
        }

        // Split the last run that contains the match if there is any text left.
        if ((currentNode != null) && (remainingLength > 0))
        {
            SplitRun((Run)currentNode, remainingLength);
            runs.Add(currentNode);
        }

        // To do
        Document doc = ((Document)e.MatchNode.Document);
        Bookmark bm = doc.Range.Bookmarks[BookmarkName.ToString()];
        Paragraph bmPara = (Paragraph)bm.BookmarkStart.GetAncestor(NodeType.Paragraph);

        if (bmPara != null)
        {
            int bmParaIndex = doc.GetChildNodes(NodeType.Paragraph, true).IndexOf(bmPara);
            Paragraph start = ((Run)runs[0]).ParentParagraph;
            int searchTextParaIndex = doc.GetChildNodes(NodeType.Paragraph, true).IndexOf(start);

            if (searchTextParaIndex > bmParaIndex)
            {
                Table targetTable = null;
                CompositeNode node = (CompositeNode)start;
                bool flag = true;

                while (node != null && flag)
                {
                    if (node.NodeType == NodeType.Table)
                    {
                        Table table = (Table)node;
                        if (table.Title == TableTitle)
                        {
                            targetTable = table;
                            flag = false;
                            break;
                        }
                    }

                    node = (CompositeNode)node.NextSibling;
                }

                if (targetTable != null)
                {
                    TheTable = targetTable;
                }
            }
        }

        return ReplaceAction.Skip;
    }

    private static Run SplitRun(Run run, int position)
    {
        Run afterRun = (Run)run.Clone(true);
        afterRun.Text = run.Text.Substring(position);
        run.Text = run.Text.Substring((0), (0) + (position));
        run.ParentNode.InsertAfter(afterRun, run);
        return afterRun;
    }
}

private static void InsertTableRow(string rowFilenameAndPath,
                                    string tableFilenameAndPath,
                                    string outputFilenameAndPath,
                                    string bookmarkName,
                                    string tableTitle,
                                    string searchText)
{
    Document tableDoc = new Document(tableFilenameAndPath);
    Document rowDoc = new Document(rowFilenameAndPath);

    // Get the row to be appended
    // index is hard coded here because there will always be only one row
    NodeImporter imp = new NodeImporter(rowDoc, tableDoc, ImportFormatMode.KeepSourceFormatting);
    Node impNode = imp.ImportNode(rowDoc.FirstSection.Body.Tables[0].Rows[0], true);

    FindReplaceOptions options = new FindReplaceOptions();
    FindAndReplace findAndReplace = new FindAndReplace
    {
        BookmarkName = bookmarkName,
        TableTitle = tableTitle,
        SearchText = searchText
    };

    options.ReplacingCallback = findAndReplace;
    tableDoc.Range.Replace(new Regex(searchText), "", options);

    Table targetTable = findAndReplace.TheTable;
    if (targetTable != null)
    {
        targetTable.Rows.Add(impNode);
    }

    tableDoc.Save(outputFilenameAndPath);
}

Hope, this helps in achieving what you are looking for.