Ootempl.Table (ootempl v0.3.0)
Table structure detection and analysis for Word documents.
This module provides functionality to detect Word tables in XML, extract rows, analyze placeholders within table cells, and identify template rows based on whether they reference list data.
Template Row Detection
Template rows are identified by analyzing placeholders in each row:
- If a placeholder references a list in the data structure (e.g.,
@claims.id@whereclaimsis a list), the row is considered a template row - Multiple consecutive rows referencing the same list are grouped as multi-row templates
- If a row references multiple different lists, an error is returned
Word XML Structure
Tables in Word XML follow this structure:
<w:tbl>
<w:tr> <!-- table row -->
<w:tc> <!-- table cell -->
<w:p> <!-- paragraph -->
<w:r><w:t>@claims.id@</w:t></w:r>
</w:p>
</w:tc>
</w:tr>
</w:tbl>Examples
# Find all tables in document
tables = Ootempl.Table.find_tables(xml_doc)
# Extract rows from a table
rows = Ootempl.Table.extract_rows(table)
# Analyze a row to determine if it's a template
data = %{"claims" => [%{"id" => 1}, %{"id" => 2}]}
result = Ootempl.Table.analyze_row(row, data)
# => {:ok, %{row: row, template?: true, list_key: "claims", placeholders: [...]}}
# Group consecutive template rows
grouped = Ootempl.Table.group_template_rows(rows, data)
Summary
Functions
Duplicates template rows for each item in a list with proper data scoping.
Extracts all row elements from a table.
Finds all table elements in the given XML document.
Groups consecutive template rows that reference the same list.
Inserts duplicated rows into a table at the specified position.
Removes template rows from a table.
Types
@type row_analysis() :: %{ row: Ootempl.Xml.xml_element(), template?: boolean(), list_key: String.t() | nil, placeholders: [Ootempl.Placeholder.placeholder()] }
Functions
@spec duplicate_rows([Ootempl.Xml.xml_element()], String.t(), map()) :: [ {Ootempl.Xml.xml_element(), map()} ]
Duplicates template rows for each item in a list with proper data scoping.
This is the core transformation for dynamic table generation. It takes a set of template rows (which may be a single row or multiple consecutive rows referencing the same list), clones them for each item in the list data, and creates scoped data contexts for each duplicated row group.
Parameters
template_rows- List of row XML elements that form the template (1+ consecutive rows)list_key- The key in the data structure that references the listdata- The full data structure containing both the list and parent context
Returns
- A list of tuples
{row_element, scoped_data}where each row is paired with its corresponding data context for placeholder replacement
Examples
# Single template row
template_rows = [row_with_placeholder]
list_key = "claims"
data = %{"first_name" => "John", "claims" => [%{"id" => 1}, %{"id" => 2}]}
duplicate_rows(template_rows, list_key, data)
# => [
# {cloned_row1, %{"first_name" => "John", "id" => 1}},
# {cloned_row2, %{"first_name" => "John", "id" => 2}}
# ]
# Multi-row template
template_rows = [header_row, detail_row]
list_key = "orders"
data = %{"company" => "Acme", "orders" => [%{"id" => 100}, %{"id" => 200}]}
duplicate_rows(template_rows, list_key, data)
# => [
# {cloned_header1, %{"company" => "Acme", "id" => 100}},
# {cloned_detail1, %{"company" => "Acme", "id" => 100}},
# {cloned_header2, %{"company" => "Acme", "id" => 200}},
# {cloned_detail2, %{"company" => "Acme", "id" => 200}}
# ]
# Empty list
duplicate_rows(template_rows, "claims", %{"claims" => []})
# => []
@spec extract_rows(Ootempl.Xml.xml_element()) :: [Ootempl.Xml.xml_element()]
Extracts all row elements from a table.
Finds all <w:tr> (Word table row) elements within a table.
Parameters
table_element- The table XML element
Returns
- A list of row XML elements
Examples
rows = Ootempl.Table.extract_rows(table)
# => [row1, row2, row3, ...]
@spec find_tables(Ootempl.Xml.xml_element()) :: [Ootempl.Xml.xml_element()]
Finds all table elements in the given XML document.
Recursively searches for <w:tbl> elements (Word table elements) in the XML tree.
Parameters
xml_element- The XML element to search (typically the document root)
Returns
- A list of table XML elements
Examples
tables = Ootempl.Table.find_tables(doc)
# => [table1, table2, ...]
@spec group_template_rows([Ootempl.Xml.xml_element()], map()) :: {:ok, [row_analysis()]} | {:error, {:multiple_lists, Ootempl.Xml.xml_element()}}
Groups consecutive template rows that reference the same list.
Analyzes all rows and groups consecutive template rows that reference the same list key together. Non-template rows and template rows referencing different lists break the grouping.
Parameters
rows- List of row XML elementsdata- The data structure to check against
Returns
{:ok, grouped_analyses}- List of row analyses with grouping information{:error, {:multiple_lists, row}}- A row references multiple lists
Examples
rows = [regular_row, template_row1, template_row2, regular_row2]
data = %{"claims" => [...]}
Ootempl.Table.group_template_rows(rows, data)
# => {:ok, [
# %{template?: false, ...},
# %{template?: true, list_key: "claims", ...},
# %{template?: true, list_key: "claims", ...},
# %{template?: false, ...}
# ]}
@spec insert_rows( Ootempl.Xml.xml_element(), [Ootempl.Xml.xml_element()], non_neg_integer() ) :: Ootempl.Xml.xml_element()
Inserts duplicated rows into a table at the specified position.
Replaces the template rows in the table with the duplicated rows. The position should be the index of the first template row in the table's row list.
Parameters
table_element- The table XML elementduplicated_rows- List of row XML elements to insertposition- Zero-based index where template rows start
Returns
- Updated table XML element with duplicated rows inserted
Examples
table = find_tables(doc) |> hd()
duplicated = duplicate_rows(template_rows, "claims", data)
rows_only = Enum.map(duplicated, fn {row, _data} -> row end)
updated_table = insert_rows(table, rows_only, 1)
@spec remove_template_rows(Ootempl.Xml.xml_element(), [Ootempl.Xml.xml_element()]) :: Ootempl.Xml.xml_element()
Removes template rows from a table.
Deletes the specified template rows from the table's content. This is typically called after duplicated rows have been inserted to clean up the original template.
Parameters
table_element- The table XML elementtemplate_rows- List of template row XML elements to remove
Returns
- Updated table XML element with template rows removed
Examples
table = find_tables(doc) |> hd()
template_rows = [row1, row2]
updated_table = remove_template_rows(table, template_rows)