1###############################################################################
2#
3# Table - A class for writing the Excel XLSX Worksheet file.
4#
5# SPDX-License-Identifier: BSD-2-Clause
6#
7# Copyright (c) 2013-2025, John McNamara, jmcnamara@cpan.org
8#
9
10from . import xmlwriter
11
12
13class Table(xmlwriter.XMLwriter):
14 """
15 A class for writing the Excel XLSX Table file.
16
17
18 """
19
20 ###########################################################################
21 #
22 # Public API.
23 #
24 ###########################################################################
25
26 def __init__(self):
27 """
28 Constructor.
29
30 """
31
32 super().__init__()
33
34 self.properties = {}
35
36 ###########################################################################
37 #
38 # Private API.
39 #
40 ###########################################################################
41
42 def _assemble_xml_file(self):
43 # Assemble and write the XML file.
44
45 # Write the XML declaration.
46 self._xml_declaration()
47
48 # Write the table element.
49 self._write_table()
50
51 # Write the autoFilter element.
52 self._write_auto_filter()
53
54 # Write the tableColumns element.
55 self._write_table_columns()
56
57 # Write the tableStyleInfo element.
58 self._write_table_style_info()
59
60 # Close the table tag.
61 self._xml_end_tag("table")
62
63 # Close the file.
64 self._xml_close()
65
66 def _set_properties(self, properties):
67 # Set the document properties.
68 self.properties = properties
69
70 ###########################################################################
71 #
72 # XML methods.
73 #
74 ###########################################################################
75
76 def _write_table(self):
77 # Write the <table> element.
78 schema = "http://schemas.openxmlformats.org/"
79 xmlns = schema + "spreadsheetml/2006/main"
80 table_id = self.properties["id"]
81 name = self.properties["name"]
82 display_name = self.properties["name"]
83 ref = self.properties["range"]
84 totals_row_shown = self.properties["totals_row_shown"]
85 header_row_count = self.properties["header_row_count"]
86
87 attributes = [
88 ("xmlns", xmlns),
89 ("id", table_id),
90 ("name", name),
91 ("displayName", display_name),
92 ("ref", ref),
93 ]
94
95 if not header_row_count:
96 attributes.append(("headerRowCount", 0))
97
98 if totals_row_shown:
99 attributes.append(("totalsRowCount", 1))
100 else:
101 attributes.append(("totalsRowShown", 0))
102
103 self._xml_start_tag("table", attributes)
104
105 def _write_auto_filter(self):
106 # Write the <autoFilter> element.
107 autofilter = self.properties.get("autofilter", 0)
108
109 if not autofilter:
110 return
111
112 attributes = [
113 (
114 "ref",
115 autofilter,
116 )
117 ]
118
119 self._xml_empty_tag("autoFilter", attributes)
120
121 def _write_table_columns(self):
122 # Write the <tableColumns> element.
123 columns = self.properties["columns"]
124
125 count = len(columns)
126
127 attributes = [("count", count)]
128
129 self._xml_start_tag("tableColumns", attributes)
130
131 for col_data in columns:
132 # Write the tableColumn element.
133 self._write_table_column(col_data)
134
135 self._xml_end_tag("tableColumns")
136
137 def _write_table_column(self, col_data):
138 # Write the <tableColumn> element.
139 attributes = [
140 ("id", col_data["id"]),
141 ("name", col_data["name"]),
142 ]
143
144 if col_data.get("total_string"):
145 attributes.append(("totalsRowLabel", col_data["total_string"]))
146 elif col_data.get("total_function"):
147 attributes.append(("totalsRowFunction", col_data["total_function"]))
148
149 if "format" in col_data and col_data["format"] is not None:
150 attributes.append(("dataDxfId", col_data["format"]))
151
152 if col_data.get("formula") or col_data.get("custom_total"):
153 self._xml_start_tag("tableColumn", attributes)
154
155 if col_data.get("formula"):
156 # Write the calculatedColumnFormula element.
157 self._write_calculated_column_formula(col_data["formula"])
158
159 if col_data.get("custom_total"):
160 # Write the totalsRowFormula element.
161 self._write_totals_row_formula(col_data.get("custom_total"))
162
163 self._xml_end_tag("tableColumn")
164 else:
165 self._xml_empty_tag("tableColumn", attributes)
166
167 def _write_table_style_info(self):
168 # Write the <tableStyleInfo> element.
169 props = self.properties
170 attributes = []
171
172 name = props["style"]
173 show_first_column = 0 + props["show_first_col"]
174 show_last_column = 0 + props["show_last_col"]
175 show_row_stripes = 0 + props["show_row_stripes"]
176 show_column_stripes = 0 + props["show_col_stripes"]
177
178 if name is not None and name != "" and name != "None":
179 attributes.append(("name", name))
180
181 attributes.append(("showFirstColumn", show_first_column))
182 attributes.append(("showLastColumn", show_last_column))
183 attributes.append(("showRowStripes", show_row_stripes))
184 attributes.append(("showColumnStripes", show_column_stripes))
185
186 self._xml_empty_tag("tableStyleInfo", attributes)
187
188 def _write_calculated_column_formula(self, formula):
189 # Write the <calculatedColumnFormula> element.
190 self._xml_data_element("calculatedColumnFormula", formula)
191
192 def _write_totals_row_formula(self, formula):
193 # Write the <totalsRowFormula> element.
194 self._xml_data_element("totalsRowFormula", formula)