Add tables to word processing documents
Tables are inserted as <w:tbl/> elements in the main document body. A table contains rows, cells, and usually paragraphs inside each cell.
The caller typically supplies a rectangular collection of strings. A writer turns each outer item into a table row and each value into a table cell containing at least one paragraph and run.
Table markup
<w:tbl>
<w:tblPr>
<w:tblBorders>
<w:top w:val="single" w:sz="12"/>
<w:bottom w:val="single" w:sz="12"/>
<w:left w:val="single" w:sz="12"/>
<w:right w:val="single" w:sz="12"/>
<w:insideH w:val="single" w:sz="12"/>
<w:insideV w:val="single" w:sz="12"/>
</w:tblBorders>
</w:tblPr>
<w:tr>
<w:tc>
<w:tcPr><w:tcW w:type="auto"/></w:tcPr>
<w:p><w:r><w:t>Cell text</w:t></w:r></w:p>
</w:tc>
</w:tr>
</w:tbl>
In ooxmlsdk, generated schema types include Table, TableProperties, TableBorders, TableRow, TableCell, TableCellProperties, TableCellWidth, Paragraph, Run, and Text.
Rust workflow
#![allow(unused)] fn main() { pub fn insert_table(path: &Path, rows: &[&[&str]]) -> Result<Vec<u8>, Box<dyn std::error::Error>> { let mut document = WordprocessingDocument::new_from_file_with_settings(path, lazy_settings())?; let main_part = document.main_document_part()?; let xml = main_part.data_as_str(&document)?.unwrap_or_default(); let table = table_xml(rows); let updated_xml = insert_before_section_properties(xml, &table)?; main_part.set_data(&mut document, updated_xml.into_bytes())?; let mut buffer = Cursor::new(Vec::new()); document.save(&mut buffer)?; Ok(buffer.into_inner()) } }
The listing creates a simple table from string rows and cells, then inserts it before the body section properties (<w:sectPr/>) if that element is present at the end of the body.
A production table writer can extend this with table properties, borders, widths, grid columns, and style ids. Appending after section properties can produce invalid or surprising document structure.