Add/Delete Table from Word

I have a requirement to add multiple tables to a Word document at specific bookmark within the document. I need to delete the existing table at the bookmark and insert the new table when saving. I also need to be able to read the table when loading the doc and write the Table to a DataTable. Writing the table from a datatable at the bookmark is working, but when I always get an error when I attempted to remove existing. I’ve tried two different methods (1st & 2nd attempt) and both error when it tried to save the Word.

Here’s the error: {"Cannot remove because there is no parent{"Cannot remove because there is no parent"}

Here’s the code.

public static MemoryStream AddTableToWord(SPFile spfAPDocument, Dictionary<string, System.Data.DataTable> dctTables, double ColWidth, bool IncludeHeader)
{
    System.Data.DataTable dt = new System.Data.DataTable();
    APUtil.SetAsposeWordLicense();

    Aspose.Words.Document wrdAPDoc = new Aspose.Words.Document(spfAPDocument.OpenBinaryStream());

    foreach (KeyValuePair<string, System.Data.DataTable> kvp in dctTables)
    {
        //remove
        existing table \*1st attempt

        //Aspose.Words.Bookmark
        bk = wrdAPDoc.Range.Bookmarks[kvp.Key];

        //if
        (bk != null)
        {

            // Node tblOld =
            bk.BookmarkStart.GetAncestor(NodeType.Table);
            // if (tblOld != null)
            // tblOld.Remove();
            //}
            DocumentBuilder builder = new DocumentBuilder(wrdAPDoc);

            builder.MoveToBookmark(kvp.Key);

            // 2nd attempt 

            //Aspose.Words.Tables.Table
            wrdTblOld = builder.CurrentNode.GetAncestor(NodeType.Table) as Aspose.Words.Tables.Table;

            //if
            (wrdTblOld != null)
        //{
        // wrdTblOld.Remove();
        //}


            //Aspose.Words.Bookmark
            bookmark = wrdAPDoc.Range.Bookmarks[kvp.Key];

            //Node parentParagraph =
            bookmark.BookmarkStart.ParentNode;

            //if (parentParagraph != null)
            //{
            // //If next node is Table then remove it
            // if (parentParagraph.NextSibling.NodeType ==  NodeType.Table)
            // {
            // parentParagraph.NextSibling.Remove();
            // }
        }
        dt = (System.Data.DataTable)kvp.Value;

        Aspose.Words.Tables.Table wrdTable =
        builder.StartTable();

        builder.ParagraphFormat.Alignment = ParagraphAlignment.Center;

        if (IncludeHeader)
        {
            builder.Font.Bold = true;
            foreach (DataColumn dc in dt.Columns)
            {
                //if (!dc.ColumnName.EndsWith("ID"))
                //{
                builder.InsertCell();
                builder.Writeln(dc.ColumnName);
                //}
            }
            builder.EndRow();
        }

        wrdTable.Alignment =
        Aspose.Words.Tables.TableAlignment.Center;

        wrdTable.StyleIdentifier = StyleIdentifier.MediumGrid2Accent1;

        wrdTable.StyleOptions =
        Aspose.Words.Tables.TableStyleOptions.FirstRow | Aspose.Words.Tables.TableStyleOptions.RowBands
        | Aspose.Words.Tables.TableStyleOptions.LastColumn;

        builder.Font.Bold = false;
        foreach (DataRow dr in dt.Rows)
        {
            foreach (object item in dr.ItemArray)
            {
                builder.InsertCell();
                switch
                (item.GetType().Name)
                {
                    case "Byte[]":
                        Aspose.Words.Drawing.Shape shape = builder.InsertImage((byte[])item, 50, 50);
                        break;
                    case "DateTime":
                        DateTime dDate;
                        if (DateTime.TryParse(item.ToString(),
                        out dDate))
                        {
                            builder.Write(dDate.ToShortDateString());
                        }
                        break;
                    default:
                        builder.Write(item.ToString());
                        break;
                }
            }
            builder.EndRow();
        }

        builder.EndTable();

        wrdTable.AutoFit(Aspose.Words.Tables.AutoFitBehavior.AutoFitToContents);


        //wrdTable.FirstRow.LastCell.RemoveAllChildren
    }
    MemoryStream ms = new MemoryStream();
    wrdAPDoc.Save(ms, Aspose.Words.SaveFormat.Docx);

    return ms;
}

Hi Tan,

Thanks for your inquiry. It would be great if you please share following detail for investigation purposes.

  • Please attach your input Word document.
  • Please

create a standalone/runnable simple application (for example a Console
Application Project
) that demonstrates the code (Aspose.Words code) you used to generate
your output document

  • Please
    attach your target Word document showing the desired behavior. You can
    use Microsoft Word to create your target Word document. I will
    investigate as to how you are expecting your final document be generated
    like.

As soon as you get these pieces of information to
us we’ll start our investigation into your issue.

Here’s the sample template that has two bookmark, tblContractHistory and tblRisk where the table needs to be added, read from, and delete.

Hi Tan,

Thanks for your inquiry. Please use the following code example to move the cursor to the bookmark and insert new table.

Document doc = new Document(MyDir + "AP.docx");
DocumentBuilder builder = new DocumentBuilder(doc);
builder.MoveToBookmark("tblContractHistory");
// We call this method to start building the table.
builder.StartTable();
builder.InsertCell();
builder.Write("Row 1, Cell 1 Content.");
// Build the second cell
builder.InsertCell();
builder.Write("Row 1, Cell 2 Content.");
// Call the following method to end the row and start a new row.
builder.EndRow();
// Build the first cell of the second row.
builder.InsertCell();
builder.Write("Row 2, Cell 1 Content");
// Build the second cell.
builder.InsertCell();
builder.Write("Row 2, Cell 2 Content.");
builder.EndRow();
// Signal that we have finished building the table.
builder.EndTable();
doc.Save(MyDir + "Out.docx");

The shared bookmark are not inside a table. However, you can use the following code example to get the table node having bookmark inside and remove the table node.

Document doc = new Document(MyDir + "AP.docx");
DocumentBuilder builder = new DocumentBuilder(doc);
//Get table using bookmark
Table table = (Table)doc.Range.Bookmarks["tblContractHistory"].BookmarkStart.GetAncestor(NodeType.Table);
if (table != null)
{
    //Remove table
    table.Remove();
}

You may use following code example to create data from DataTable.

Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
DataTable dataTable = GetDate();
// Build a table in the document from the data contained in the DataTable.
Table table = CreateTableFromDataTable(builder, dataTable, true);
// We can apply a table style as a very quick way to format the entire table.
table.StyleIdentifier = StyleIdentifier.MediumList2Accent1;
table.StyleOptions = TableStyleOptions.FirstRow | TableStyleOptions.RowBands | TableStyleOptions.LastColumn;
doc.Save(MyDir + "Out.docx");
/// 
/// Imports the content from the specified DataTable into a new Aspose.Words table object. The table is inserted at the current position
/// of the document builder and using the current builder's formatting if any is defined.
/// 
public static Table CreateTableFromDataTable(DocumentBuilder builder, DataTable dataTable, bool importColumnHeadings)
{
    Document doc = builder.Document;
    Table table = builder.StartTable();
    // Check if the names of the columns from the data source are to be included in a header row.
    if (importColumnHeadings)
    {
        // Store the original values of these properties before changing them.
        bool boldValue = builder.Font.Bold;
        ParagraphAlignment paragraphAlignmentValue = builder.ParagraphFormat.Alignment;
        // Format the heading row with the appropriate properties.
        builder.Font.Bold = true;
        builder.ParagraphFormat.Alignment = ParagraphAlignment.Center;
        // Create a new row and insert the name of each column into the first row of the table.
        foreach (DataColumn column in dataTable.Columns)
        {
            builder.InsertCell();
            builder.Writeln(column.ColumnName);
        }
        builder.EndRow();
        // Restore the original formatting.
        builder.Font.Bold = boldValue;
        builder.ParagraphFormat.Alignment = paragraphAlignmentValue;
    }
    foreach (DataRow dataRow in dataTable.Rows)
    {
        foreach (object item in dataRow.ItemArray)
        {
            // Insert a new cell for each object.
            builder.InsertCell();
            switch (item.GetType().Name)
            {
                case "Byte[]":
                    // Assume a byte array is an image. Other data types can be added here.
                    Shape shape = builder.InsertImage((byte[])item, 50, 50);
                    break;
                case "DateTime":
                    // Define a custom format for dates and times.
                    DateTime dateTime = (DateTime)item;
                    builder.Write(dateTime.ToString("MMMM d, yyyy"));
                    break;
                default:
                    // By default any other item will be inserted as text.
                    builder.Write(item.ToString());
                    break;
            }
        }
        // After we insert all the data from a DataRow when can end the table row.
        builder.EndRow();
    }
    // We have finished inserting all the data from the DataTable, we can end the table.
    builder.EndTable();
    return table;
}

public static DataTable GetDate()
{
    //Create table with data
    DataTable table = new DataTable();
    table.Columns.Add("Col1");
    table.Columns.Add("Col2");
    table.Columns.Add("Col3");
    table.Columns.Add("Col4");
    table.Columns.Add("Col5");
    table.Columns.Add("Col6");
    for (int i = 0; i < 10; i++)
    {
        DataRow row = table.NewRow();
        row[0] = "Nameplate unit kW (kW)";
        row[1] = i.ToString() + "0";
        row[2] = i.ToString() + "1";
        row[3] = i.ToString() + "2";
        row[4] = i.ToString() + "3";
        row[5] = i.ToString() + "4";
        table.Rows.Add(row);
    }
    return table;
}

Hope this helps you. Please let us know if you have any more queries.

Thanks or the reply. I was able to insert into the Word document based on the bookmark previously, but had a difficult time getting the table from word at the bookmark. When I tried it get the Table, it was always null. I ended up embedding the bookmark into the table but when I delete the table to replace place it, the bookmark is deleted also. I also need to read from the current table to convert it to a datatable.

Here’s a rough process flow of what I’m attempting to do.

When a user open a web form, it reads from the word and get the table. Convert the table to datatable and bind it to a gridview. When the user saves the form, it takes the gridview updates and save the table back to Word, replacing the previous table at the bookmark.

Hi Tan,

Thanks for sharing the detail. Please use the following code example to achieve your requirements. Hope this helps you.

  1. Following code example move the cursor to the bookmark ‘tblContractHistory’ and insert table. This code example also change the position of bookmark to inside of first cell of table.
Document doc = new Document(MyDir + "AP.docx");
DocumentBuilder builder = new DocumentBuilder(doc);
builder.MoveToBookmark("tblContractHistory");
// We call this method to start building the table.
builder.StartTable();
builder.InsertCell();
builder.StartBookmark("tblContractHistory");
builder.EndBookmark("tblContractHistory");
builder.Write("Row 1, Cell 1 Content.");
// Build the second cell
builder.InsertCell();
builder.Write("Row 1, Cell 2 Content.");
// Call the following method to end the row and start a new row.
builder.EndRow();
// Build the first cell of the second row.
builder.InsertCell();
builder.Write("Row 2, Cell 1 Content");
// Build the second cell.
builder.InsertCell();
builder.Write("Row 2, Cell 2 Content.");
builder.EndRow();
// Signal that we have finished building the table.
builder.EndTable();
doc.Save(MyDir + "Create.Table.at.Bookmark.docx");
  1. Following code example removes the table which contains the bookmark ‘tblContractHistory’ and insert new table at same location.
Document doc2 = new Document(MyDir + "Create.Table.at.Bookmark.docx");
DocumentBuilder builder2 = new DocumentBuilder(doc2);
//Get table using bookmark
Table table = (Table)doc2.Range.Bookmarks["tblContractHistory"].BookmarkStart.GetAncestor(NodeType.Table);
if (table != null)
{
    Paragraph para = new Paragraph(doc2);
    para.AppendChild(new Run(doc2));
    table.ParentNode.InsertAfter(para, table);
    builder2.MoveTo(para);
    // We call this method to start building the table.
    builder2.StartTable();
    builder2.InsertCell();
    builder2.StartBookmark("tblContractHistory");
    builder2.EndBookmark("tblContractHistory");
    builder2.Write("Row 1, Cell 1 Content.");
    // Build the second cell
    builder2.InsertCell();
    builder2.Write("Row 1, Cell 2 new Content.");
    // Call the following method to end the row and start a new row.
    builder2.EndRow();
    // Build the first cell of the second row.
    builder2.InsertCell();
    builder2.Write("Row 2, Cell 1 newContent");
    // Build the second cell.
    builder2.InsertCell();
    builder2.Write("Row 2, Cell 2 new Content.");
    builder2.EndRow();
    // Signal that we have finished building the table.
    builder2.EndTable();
    //Remove table
    table.Remove();
    //remove paragraph
    para.Remove();
}
doc2.Save(MyDir + "Create.New.Table.at.Bookmark.docx");

Thanks for providing the sample code. It works great.

Do you have sample code to get the table from word and convert to datatable?

I tried the below and I was able to get the table. However, it only got the first 2 columns of the table of the first row and nothing else.

Aspose.Words.Document wrdAPDoc = new Aspose.Words.Document(spfAPFile.OpenBinaryStream());

DocumentBuilder builder = new DocumentBuilder(wrdAPDoc);

Aspose.Words.Bookmark bkm = wrdAPDoc.Range.Bookmarks[CntCtrlName];

if (bkm != null)

{

    Aspose.Words.Tables.Table table = (Aspose.Words.Tables.Table)bkm.BookmarkStart.GetAncestor(NodeType.Table);

    if (table != null)

    {

        char[] escArr = { '\a' };

        foreach (Aspose.Words.Tables.Cell cell in table.FirstRow.Cells)

        {

            dt.Columns.Add(cell.Range.Text.Trim(escArr));

        }

        for (int i = 1; i < table.Rows.Count; i++)

        {

            DataRow row = dt.NewRow();

            for (int j = 0; j < table.Rows[i].Cells.Count; j++)

            {

                row[j] =
                table.Rows[i].Cells[j].Range.Text.Trim(escArr);

            }

            dt.Rows.Add(row);

        }

    }

}

Hi Tan,

Thanks for your inquiry.

I have tested the scenario using latest version of Aspose.Words for .NET 14.7.0 and have not found the shared issue. I used the following code example to test this issue. Please use the Aspose.Words for .NET 14.7.0 and try following code example. Let us know if you have any more queries.

Document doc = new Document(MyDir + "Default-2014-09-05-133916-R0.docx");

DocumentBuilder builder = new DocumentBuilder(doc);

DataTable dt = new DataTable();

Bookmark bkm = doc.Range.Bookmarks["tblContract"];

Aspose.Words.Tables.Table table = (Aspose.Words.Tables.Table)bkm.BookmarkStart.GetAncestor(NodeType.Table);

if (table != null)

{

    foreach (Aspose.Words.Tables.Cell cell in table.FirstRow.Cells)

    {

        dt.Columns.Add(cell.ToString(SaveFormat.Text).Trim());

    }

    for (int i = 1; i < table.Rows.Count; i++)

    {

        DataRow row = dt.NewRow();

        for (int j = 0; j < table.Rows[i].Cells.Count; j++)

        {

            row[j] = table.Rows[i].Cells[j].ToString(SaveFormat.Text).Trim();

        }

        dt.Rows.Add(row);

    }

}

I’m currently using 14.7.0 of Aspose.Words.

Is it possible to set the table as readonly?

Since the only way to lock the table is to place it inside a content control, how can I add the same table inside a RichText content control at the same bookmark location?

StructuredDocumentTag ctrlField = (StructuredDocumentTag)wrdAPDoc.Range.Bookmarks[kvp.Key].BookmarkStart.GetAncestor(NodeType.StructuredDocumentTag);
if (ctrlField != null)
{
    ctrlField.ChildNodes.Remove(ctrlField.GetChild(NodeType.Table, 1, true));
    Aspose.Words.Paragraph para = new Aspose.Words.Paragraph(wrdAPDoc);
    para.AppendChild(new Aspose.Words.Run(wrdAPDoc));
    ctrlField.ParentNode.InsertAfter(para, ctrlField);
    builder.MoveTo(para);
    CreateWordTable(builder, IncludeHeader, dt, kvp.Key);
    ctrlField.LockContentControl = true;
    ctrlField.LockContents = true;
    //ctrlField.Remove();
    para.Remove();
}

So I have the above code to add the table. If I leave the ctrField.Remove(), the control fields ends up being remove. I only want the content of the control to be remove.

Hi Tan,

Thanks for your inquiry.

phamtq:

Is it possible to set the table as readonly?
Since the only way to lock the table is to place it inside a content control, how can I add the same table inside a RichText content control at the same bookmark location?

Unfortunately, Aspose.Words does not support the requested feature (protect the part of document) at
the moment. However, we have already logged this feature request as WORDSNET-9000
in our issue tracking system. You will be notified via this forum
thread once this feature is available. We apologize for your
inconvenience.

phamtq:

So I have the above code to add the table. If I leave the ctrField.Remove(), the control fields ends up being remove. I only want the content of the control to be remove.

Please use CompositeNode.RemoveAllChildren method to remove all the child nodes of the current node.

Thanks for all the help. There’s something I noticed from the code above. Each time the document is save after inserting the table in the content control, the content control adds additional Paragraph inside the control. How do I make sure that it doesn’t have extra paragraph after the table?

Hi Tan,

Thanks for your inquiry. Unfortunately, I have not understood your query. It would be great if you please share following detail for investigation purposes.

  • Please attach your input Word document.
  • Please

create a standalone/runnable simple application (for example a Console
Application Project
) that demonstrates the code (Aspose.Words code) you used to generate
your output document

  • Please attach the output Word file that shows the undesired behavior.
  • Please
    attach your target Word document showing the desired behavior. You can
    use Microsoft Word to create your target Word document. I will
    investigate as to how you are expecting your final document be generated
    like.

As soon as you get these pieces of information to
us we’ll start our investigation into your issue.

StructuredDocumentTag
ctrlField = (StructuredDocumentTag)bkm.BookmarkStart.GetAncestor(NodeType.StructuredDocumentTag);
if (ctrlField != null)
{
    Node[] arrNodes = ctrlField.ChildNodes.ToArray();
    if (arrNodes.Length > 1)
    {
        Node currNode = ctrlField.FirstChild;
        while (ctrlField.ChildNodes.Count > 1 && currNode != null)
        {
            if (currNode.NodeType == NodeType.Paragraph)
            {
                currNode.Remove();
                currNode = ctrlField.FirstChild;
            }
            else
                currNode = currNode.NextSibling;
        }
    }
}

Hi Tan,

Unfortunately, it is difficult to say what the problem is without the Document(s) and simplified application. We need your Document(s) and simple project to reproduce the problem. Please share the detail requested here:
https://forum.aspose.com/t/51563

As soon as you get these pieces of information to us we’ll start our investigation into your issue.

The issues you have found earlier (filed as WORDSNET-9000) have been fixed in this .NET update and this Java update.


This message was posted using Notification2Forum from Downloads module by aspose.notifier.
(12)