Add tables to word processing documents
This topic shows how to use the classes in the Open XML SDK for Office to programmatically add a table to a word processing document. It contains an example AddTable
method to illustrate this task.
AddTable method
You can use the AddTable
method to add a simple table to a word processing document. The AddTable
method accepts two parameters, indicating the following:
The name of the document to modify (string).
A two-dimensional array of strings to insert into the document as a table.
static void AddTable(string fileName, string[,] data)
Call the AddTable method
The AddTable
method modifies the document you specify, adding a table that contains the information in the two-dimensional array that you provide. To call the method, pass both of the parameter values, as shown in the following code.
string fileName = args[0];
AddTable(fileName, new string[,] {
{ "Hawaii", "HI" },
{ "California", "CA" },
{ "New York", "NY" },
{ "Massachusetts", "MA" }
});
How the code works
The following code starts by opening the document, using the Open method and indicating that the document should be open for read/write access (the final true
parameter value). Next the code retrieves a reference to the root element of the main document part, using the Document property of theMainDocumentPart of the word processing document.
using (var document = WordprocessingDocument.Open(fileName, true))
{
if (document.MainDocumentPart is null || document.MainDocumentPart.Document.Body is null)
{
throw new ArgumentNullException("MainDocumentPart and/or Body is null.");
}
var doc = document.MainDocumentPart.Document;
Create the table object and set its properties
Before you can insert a table into a document, you must create the Table object and set its properties. To set a table's properties, you create and supply values for a TableProperties object. The TableProperties
class provides many table-oriented properties, like Shading, TableBorders, TableCaption, TableCellProperties, TableJustification, and more. The sample method includes the following code.
Table table = new();
TableProperties props = new(
new TableBorders(
new TopBorder
{
Val = new EnumValue<BorderValues>(BorderValues.Single),
Size = 12
},
new BottomBorder
{
Val = new EnumValue<BorderValues>(BorderValues.Single),
Size = 12
},
new LeftBorder
{
Val = new EnumValue<BorderValues>(BorderValues.Single),
Size = 12
},
new RightBorder
{
Val = new EnumValue<BorderValues>(BorderValues.Single),
Size = 12
},
new InsideHorizontalBorder
{
Val = new EnumValue<BorderValues>(BorderValues.Single),
Size = 12
},
new InsideVerticalBorder
{
Val = new EnumValue<BorderValues>(BorderValues.Single),
Size = 12
}));
table.AppendChild<TableProperties>(props);
The constructor for the TableProperties
class allows you to specify as many child elements as you like (much like the XElement constructor). In this case, the code creates TopBorder, BottomBorder, LeftBorder, RightBorder, InsideHorizontalBorder, and InsideVerticalBorder child elements, each describing one of the border elements for the table. For each element, the code sets the Val
and Size
properties as part of calling the constructor. Setting the size is simple, but setting the Val
property requires a bit more effort: this property, for this particular object, represents the border style, and you must set it to an enumerated value. To do that, create an instance of the EnumValue<T> generic type, passing the specific border type (BorderValues) as a parameter to the constructor. Once the code has set all the table border value it needs to set, it calls the AppendChild method of the table, indicating that the generic type is TableProperties i.e., it is appending an instance of the TableProperties
class, using the variable props
as the value.
Fill the table with data
Given that table and its properties, now it is time to fill the table with data. The sample procedure iterates first through all the rows of data in the array of strings that you specified, creating a new TableRow instance for each row of data. The following code shows how you create and append the row to the table. Then for each column, the code creates a new TableCell object, fills it with data, and appends it to the row.
Next, the code does the following:
- Creates a new Text object that contains a value from the array of strings.
- Passes the Text object to the constructor for a new Run object.
- Passes the Run object to the constructor for a new Paragraph object.
- Passes the Paragraph object to the Append method of the cell.
The code then appends a new TableCellProperties object to the cell. This TableCellProperties
object, like the TableProperties
object you already saw, can accept as many objects in its constructor as you care to supply. In this case, the code passes only a new TableCellWidth object, with its Type property set to TableWidthUnitValues (so that the table automatically sizes the width of each column).
for (var i = 0; i < data.GetUpperBound(0); i++)
{
var tr = new TableRow();
for (var j = 0; j < data.GetUpperBound(1); j++)
{
var tc = new TableCell();
tc.Append(new Paragraph(new Run(new Text(data[i, j]))));
// Assume you want columns that are automatically sized.
tc.Append(new TableCellProperties(
new TableCellWidth { Type = TableWidthUnitValues.Auto }));
tr.Append(tc);
}
table.Append(tr);
}
Finish up
The following code concludes by appending the table to the body of the document, and then saving the document.
doc.Body.Append(table);
Sample Code
The following is the complete AddTable code sample in C# and Visual Basic.
static void AddTable(string fileName, string[,] data)
{
if (data is not null)
{
using (var document = WordprocessingDocument.Open(fileName, true))
{
if (document.MainDocumentPart is null || document.MainDocumentPart.Document.Body is null)
{
throw new ArgumentNullException("MainDocumentPart and/or Body is null.");
}
var doc = document.MainDocumentPart.Document;
Table table = new();
TableProperties props = new(
new TableBorders(
new TopBorder
{
Val = new EnumValue<BorderValues>(BorderValues.Single),
Size = 12
},
new BottomBorder
{
Val = new EnumValue<BorderValues>(BorderValues.Single),
Size = 12
},
new LeftBorder
{
Val = new EnumValue<BorderValues>(BorderValues.Single),
Size = 12
},
new RightBorder
{
Val = new EnumValue<BorderValues>(BorderValues.Single),
Size = 12
},
new InsideHorizontalBorder
{
Val = new EnumValue<BorderValues>(BorderValues.Single),
Size = 12
},
new InsideVerticalBorder
{
Val = new EnumValue<BorderValues>(BorderValues.Single),
Size = 12
}));
table.AppendChild<TableProperties>(props);
for (var i = 0; i < data.GetUpperBound(0); i++)
{
var tr = new TableRow();
for (var j = 0; j < data.GetUpperBound(1); j++)
{
var tc = new TableCell();
tc.Append(new Paragraph(new Run(new Text(data[i, j]))));
// Assume you want columns that are automatically sized.
tc.Append(new TableCellProperties(
new TableCellWidth { Type = TableWidthUnitValues.Auto }));
tr.Append(tc);
}
table.Append(tr);
}
doc.Body.Append(table);
}
}
}