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

In the following code running the attached files, when I try and insert a table row I get the error: “'Object reference not set to an instance of an object.”

I am inserting the Error_RowTest file into Error_TableTest and Error_Output shows the expected output. What I am trying to do is find a table by title, add a new row to that table and insert the information from the row file into the table.
ERROR_RowTest.zip (79.5 KB)

This is my code…

InsertTableRow(@“c:\temp\error_rowtest.docx”, @“c:\temp\error_tabletest.docx”, “Strawberry Delight”, @“c:\temp\Error_Output.docx”);

    private static void InsertTableRow(string rowFilenameAndPath, string tableFilenameAndPath, string tableTitle, string outputFilenameAndPath)
    {

        Document tableDoc = new Document(tableFilenameAndPath);
        Document rowDoc = new Document(rowFilenameAndPath);

        NodeCollection tables = tableDoc.GetChildNodes(NodeType.Table, true);

        foreach (Aspose.Words.Tables.Table table in tables)
        {
            if (table.Title == tableTitle)
            {
                NodeImporter imp = new NodeImporter(rowDoc, tableDoc, ImportFormatMode.KeepSourceFormatting);
                Node impNode = imp.ImportNode(rowDoc.FirstSection.Body.Tables[0].Rows[0], true);
                tableDoc.FirstSection.Body.Tables[1].Rows.Add(impNode);
                break;
            }
        }

        tableDoc.Save(outputFilenameAndPath);

    }

@SCDGLC,

The document ‘ERROR_TableTest.docx’ contains only one Table inside its Body. You can add row to the end of that Table by using the following code:

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

    NodeCollection tables = tableDoc.GetChildNodes(NodeType.Table, true);

    foreach (Aspose.Words.Tables.Table table in tables)
    {
        if (table.Title == tableTitle)
        {
            NodeImporter imp = new NodeImporter(rowDoc, tableDoc, ImportFormatMode.KeepSourceFormatting);
            Node impNode = imp.ImportNode(rowDoc.FirstSection.Body.Tables[0].Rows[0], true);
            tableDoc.FirstSection.Body.Tables[0].Rows.Add(impNode);
            break;
        }
    }

    tableDoc.Save(outputFilenameAndPath);
}

Just change tableDoc.FirstSection.Body.Tables[0].Rows.Add(impNode); to tableDoc.FirstSection.Body.Tables[0].Rows.Add(impNode);

Hope, this helps.

Thank you. However in reality the document may contain any number of tables so I need the code to be generic and work no matter what index the table is. How would I do that please?

@SCDGLC,

First you need to identify your target Table. You can insert Bookmark inside the target Table and then get it using Bookmark and append row(s) to it:

Bookmark bm = tableDoc.Range.Bookmarks["bookmark"];
Table tab = (Table)bm.BookmarkStart.GetAncestor(NodeType.Table);
tab.Rows.Add(impNode);

The problem is that there will may be multiple tables under any given bookmark and it seems to me that this code would not work and assumes that there is only one table under the bookmark.

@SCDGLC,

In MS Word, you can try specifying Title and Description inside Alt Text tab of Table Properties. After that you can detect the target table by using the following code:

Table targetTable = null;
foreach(Table tab in doc.GetChildNodes(NodeType.Table, true))
{
    if (tab.Title.Equals("Table Title") && tab.Description.Equals("Table Description"))
    {
        targetTable = tab;
        break;
    }
}

if (targetTable != null)
{
    // further code
}

Hope, this helps.

This won’t work as I need to to validate the table by its title only and won’t know its description or alt text properties.

How do I keep it entirely generic and insert a row from one file into a table in another file and only find the table based on its title where the total number of tables in the target document is unknown?

Here are sample files and expected output…
ERROR_InsertRow.zip (81.1 KB)

This is how I am currently trying to do it…

InsertTableRow(@“c:\temp\error_rowtest.docx”, @“c:\temp\error_tabletest.docx”, “Strawberry Delight”, @“c:\temp\Error_Output.docx”);

private static void InsertTableRow(string rowFilenameAndPath, string tableFilenameAndPath, string tableTitle, string outputFilenameAndPath)
{

    Document tableDoc = new Document(tableFilenameAndPath);
    Document rowDoc = new Document(rowFilenameAndPath);

    NodeCollection tables = tableDoc.GetChildNodes(NodeType.Table, true);

    foreach (Aspose.Words.Tables.Table table in tables)
    {
        if (table.Title == tableTitle)
        {
            NodeImporter imp = new NodeImporter(rowDoc, tableDoc, ImportFormatMode.KeepSourceFormatting);
            Node impNode = imp.ImportNode(rowDoc.FirstSection.Body.Tables[0].Rows[0], true);
            tableDoc.FirstSection.Body.Tables[1].Rows.Add(impNode); //THIS ROW WILL NOT WORK AS THE TABLE INDEX IS HARDCODED
            break;
        }
    }

    tableDoc.Save(outputFilenameAndPath);

}

@SCDGLC,

Please try using the following code:

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

    NodeCollection tables = tableDoc.GetChildNodes(NodeType.Table, true);

    foreach (Aspose.Words.Tables.Table table in tables)
    {
        if (table.Title == tableTitle)
        {
            NodeImporter imp = new NodeImporter(rowDoc, tableDoc, ImportFormatMode.KeepSourceFormatting);
            Node impNode = imp.ImportNode(rowDoc.FirstSection.Body.Tables[0].Rows[0], true);
            table.Rows.Add(impNode); //THIS ROW WILL NOT WORK AS THE TABLE INDEX IS HARDCODED
            break;
        }
    }

    tableDoc.Save(outputFilenameAndPath);
} 

Hope, this helps.

That is great Awais, thanks, however annoyingly I realised that some documents will have tables with the same name under different bookmarks, so I need to be able to search for a bookmark, and then under that bookmark search for the table title before adding the row to the table. How would I do that please?

Here are the files with expected output:
ERROR_RowTest.zip (82.2 KB)

And here is the code I have at the moment but need to use the Bookmark parameter:

InsertTableRow(@“c:\temp\Error_row.docx”, @“c:\temp\Error_table.docx”, “Bookmark2”, “Strawberry Delight”, @“c:\temp\Error_Output.docx”);

private static void InsertTableRow(string rowFilenameAndPath, string tableFilenameAndPath, string bookmarkName, string tableTitle, string outputFilenameAndPath)
{

        Document tableDoc = new Document(tableFilenameAndPath);
        Document rowDoc = new Document(rowFilenameAndPath);

        NodeCollection tables = tableDoc.GetChildNodes(NodeType.Table, true);

        foreach (Aspose.Words.Tables.Table table in tables)
        {
            if (table.Title == tableTitle)
            {
                NodeImporter imp = new NodeImporter(rowDoc, tableDoc, ImportFormatMode.KeepSourceFormatting);
                Node impNode = imp.ImportNode(rowDoc.FirstSection.Body.Tables[0].Rows[0], true);
                table.Rows.Add(impNode); 
                break;
            }
        }

        tableDoc.Save(outputFilenameAndPath);

    }

@SCDGLC,

You can build logic on the following code to get the desired output:

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

    NodeCollection tables = tableDoc.GetChildNodes(NodeType.Table, true);

    Bookmark bm = tableDoc.Range.Bookmarks[bookmarkName];
    Paragraph start = (Paragraph)bm.BookmarkStart.GetAncestor(NodeType.Paragraph);
    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)
    {
        NodeImporter imp = new NodeImporter(rowDoc, tableDoc, ImportFormatMode.KeepSourceFormatting);
        Node impNode = imp.ImportNode(rowDoc.FirstSection.Body.Tables[0].Rows[0], true);
        targetTable.Rows.Add(impNode);
    }

    tableDoc.Save(outputFilenameAndPath);
}

Many thanks - that’s great and works.

However when I populate a content control in a cell of the added table row, when I run it locally it works, when I run it in my test environment through third party software it works, when I run in my development environment through third party software it deletes the cell containing the content control. Do you have any idea at all why, or even how, this could happen please?

chrome_SfFla9xg3y.png (15.8 KB)

@SCDGLC,

We suggest you please debug your code in your development environment to be able to identify the problematic code segment. Do you see different results when processing the same document across different environments? Are you using the same Aspose.Words versions (19.9) on all environments?

No worries, got it all sorted now, thanks for your help.

@SCDGLC,

Thanks for your feedback. It is great that you were able to find what you were looking for. Please let us know any time you have any further queries.

Oh dear, spoke to soon. Just realised you’ve hardcoded the table and row index and the following line generates the error ‘Object reference not set to an instance of an object’.

Node impNode = imp.ImportNode(rowDoc.FirstSection.Body.Tables[0].Rows[0], true);

As mentioned before, I need these to be generic as I won’t know this information at runtime. Are you able to advise, thanks.

@SCDGLC,

What I have observed so far is that your rowDoc always contains a single Table with one Row that you want to append at the end of another Table in a separate document. Can you please share your new Row document and mention what row would you like to process? Maybe you should insert a Bookmark in that row if you do not want to fetch it by its index.

The problem is that it will be different every time. So I want this code to work no matter what index the table is and no matter what index the row is - in other words totally generic.

@SCDGLC,

If you do not want to identify that Row by Bookmark, then as mentioned here in this code, you can identify that Row by using the Content Control which is contained inside it. Hope, this helps.

Thank you for your reply, however you have omitted to include the bookmark information…and I also realised even that will not be enough to uniquely identify the target table.

The problem is that I will have any number of tables with any number of rows. I need to be able to identify a table by a combination of 3 things: it’s title, what bookmark it comes under, and what text it comes after. This is because it is only the combination of those 3 things that will make a table unique. And I need all 3 things generic and not hardcoded because everything will be unknown except at runtime (i.e. tableTitle, bookmarkName, searchText as parameters).

I know how to do anyone of those things, but not the combination of all 3 at the same time, as it’s not simple to search for any one criteria within the search results of another, as Aspose often doesn’t work that way. Are you able to advise please?

@SCDGLC,

I believe, the above scenario (related to ‘Table Document’) has already been resolved. Please see my previous code snippets. The only outstanding problem is which row should be selected from the ‘Row Document’? Can you please share a ‘Row Document’ that contains more than one Rows and based on what criteria should you want to select a particular Row?