1 /*****************************************************************************
2 * table - A library for creating Excel XLSX table files.
3 *
4 * Used in conjunction with the libxlsxwriter library.
5 *
6 * Copyright 2014-2021, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
7 *
8 */
9
10 #include "xlsxwriter/xmlwriter.h"
11 #include "xlsxwriter/worksheet.h"
12 #include "xlsxwriter/table.h"
13 #include "xlsxwriter/utility.h"
14
15 /*
16 * Forward declarations.
17 */
18
19 /*****************************************************************************
20 *
21 * Private functions.
22 *
23 ****************************************************************************/
24
25 /*
26 * Create a new table object.
27 */
28 lxw_table *
lxw_table_new(void)29 lxw_table_new(void)
30 {
31 lxw_table *table = calloc(1, sizeof(lxw_table));
32 GOTO_LABEL_ON_MEM_ERROR(table, mem_error);
33
34 return table;
35
36 mem_error:
37 lxw_table_free(table);
38 return NULL;
39 }
40
41 /*
42 * Free a table object.
43 */
44 void
lxw_table_free(lxw_table * table)45 lxw_table_free(lxw_table *table)
46 {
47 if (!table)
48 return;
49
50 free(table);
51 }
52
53 /*****************************************************************************
54 *
55 * XML functions.
56 *
57 ****************************************************************************/
58
59 /*
60 * Write the XML declaration.
61 */
62 STATIC void
_table_xml_declaration(lxw_table * self)63 _table_xml_declaration(lxw_table *self)
64 {
65 lxw_xml_declaration(self->file);
66 }
67
68 /*
69 * Write the <table> element.
70 */
71 STATIC void
_table_write_table(lxw_table * self)72 _table_write_table(lxw_table *self)
73 {
74 struct xml_attribute_list attributes;
75 struct xml_attribute *attribute;
76 char xmlns[] =
77 "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
78 lxw_table_obj *table_obj = self->table_obj;
79
80 LXW_INIT_ATTRIBUTES();
81
82 LXW_PUSH_ATTRIBUTES_STR("xmlns", xmlns);
83 LXW_PUSH_ATTRIBUTES_INT("id", table_obj->id);
84
85 if (table_obj->name)
86 LXW_PUSH_ATTRIBUTES_STR("name", table_obj->name);
87 else
88 LXW_PUSH_ATTRIBUTES_STR("name", "Table1");
89
90 if (table_obj->name)
91 LXW_PUSH_ATTRIBUTES_STR("displayName", table_obj->name);
92 else
93 LXW_PUSH_ATTRIBUTES_STR("displayName", "Table1");
94
95 LXW_PUSH_ATTRIBUTES_STR("ref", table_obj->sqref);
96
97 if (table_obj->no_header_row)
98 LXW_PUSH_ATTRIBUTES_STR("headerRowCount", "0");
99
100 if (table_obj->total_row)
101 LXW_PUSH_ATTRIBUTES_STR("totalsRowCount", "1");
102 else
103 LXW_PUSH_ATTRIBUTES_STR("totalsRowShown", "0");
104
105 lxw_xml_start_tag(self->file, "table", &attributes);
106
107 LXW_FREE_ATTRIBUTES();
108 }
109
110 /*
111 * Write the <autoFilter> element.
112 */
113 STATIC void
_table_write_auto_filter(lxw_table * self)114 _table_write_auto_filter(lxw_table *self)
115 {
116 struct xml_attribute_list attributes;
117 struct xml_attribute *attribute;
118
119 if (self->table_obj->no_autofilter)
120 return;
121
122 LXW_INIT_ATTRIBUTES();
123 LXW_PUSH_ATTRIBUTES_STR("ref", self->table_obj->filter_sqref);
124
125 lxw_xml_empty_tag(self->file, "autoFilter", &attributes);
126
127 LXW_FREE_ATTRIBUTES();
128 }
129
130 /*
131 * Write the <tableColumn> element.
132 */
133 STATIC void
_table_write_table_column(lxw_table * self,uint16_t id,lxw_table_column * column)134 _table_write_table_column(lxw_table *self, uint16_t id,
135 lxw_table_column *column)
136 {
137 struct xml_attribute_list attributes;
138 struct xml_attribute *attribute;
139 int32_t dfx_id;
140
141 LXW_INIT_ATTRIBUTES();
142 LXW_PUSH_ATTRIBUTES_INT("id", id);
143
144 LXW_PUSH_ATTRIBUTES_STR("name", column->header);
145
146 if (column->total_string) {
147 LXW_PUSH_ATTRIBUTES_STR("totalsRowLabel", column->total_string);
148 }
149 else if (column->total_function) {
150 if (column->total_function == LXW_TABLE_FUNCTION_AVERAGE)
151 LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "average");
152 if (column->total_function == LXW_TABLE_FUNCTION_COUNT_NUMS)
153 LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "countNums");
154 if (column->total_function == LXW_TABLE_FUNCTION_COUNT)
155 LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "count");
156 if (column->total_function == LXW_TABLE_FUNCTION_MAX)
157 LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "max");
158 if (column->total_function == LXW_TABLE_FUNCTION_MIN)
159 LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "min");
160 if (column->total_function == LXW_TABLE_FUNCTION_STD_DEV)
161 LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "stdDev");
162 if (column->total_function == LXW_TABLE_FUNCTION_SUM)
163 LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "sum");
164 if (column->total_function == LXW_TABLE_FUNCTION_VAR)
165 LXW_PUSH_ATTRIBUTES_STR("totalsRowFunction", "var");
166 }
167
168 if (column->format) {
169 dfx_id = lxw_format_get_dxf_index(column->format);
170 LXW_PUSH_ATTRIBUTES_INT("dataDxfId", dfx_id);
171 }
172
173 if (column->formula) {
174 lxw_xml_start_tag(self->file, "tableColumn", &attributes);
175 lxw_xml_data_element(self->file, "calculatedColumnFormula",
176 column->formula, NULL);
177 lxw_xml_end_tag(self->file, "tableColumn");
178 }
179 else {
180 lxw_xml_empty_tag(self->file, "tableColumn", &attributes);
181 }
182
183 LXW_FREE_ATTRIBUTES();
184 }
185
186 /*
187 * Write the <tableColumns> element.
188 */
189 STATIC void
_table_write_table_columns(lxw_table * self)190 _table_write_table_columns(lxw_table *self)
191 {
192 struct xml_attribute_list attributes;
193 struct xml_attribute *attribute;
194 uint16_t i;
195 uint16_t num_cols = self->table_obj->num_cols;
196 lxw_table_column **columns = self->table_obj->columns;
197
198 LXW_INIT_ATTRIBUTES();
199 LXW_PUSH_ATTRIBUTES_INT("count", num_cols);
200
201 lxw_xml_start_tag(self->file, "tableColumns", &attributes);
202
203 for (i = 0; i < num_cols; i++)
204 _table_write_table_column(self, i + 1, columns[i]);
205
206 lxw_xml_end_tag(self->file, "tableColumns");
207
208 LXW_FREE_ATTRIBUTES();
209 }
210
211 /*
212 * Write the <tableStyleInfo> element.
213 */
214 STATIC void
_table_write_table_style_info(lxw_table * self)215 _table_write_table_style_info(lxw_table *self)
216 {
217 struct xml_attribute_list attributes;
218 struct xml_attribute *attribute;
219 char name[LXW_ATTR_32];
220 lxw_table_obj *table_obj = self->table_obj;
221
222 LXW_INIT_ATTRIBUTES();
223
224 if (table_obj->style_type == LXW_TABLE_STYLE_TYPE_LIGHT) {
225 if (table_obj->style_type_number != 0) {
226 lxw_snprintf(name, LXW_ATTR_32, "TableStyleLight%d",
227 table_obj->style_type_number);
228 LXW_PUSH_ATTRIBUTES_STR("name", name);
229 }
230 }
231 else if (table_obj->style_type == LXW_TABLE_STYLE_TYPE_MEDIUM) {
232 lxw_snprintf(name, LXW_ATTR_32, "TableStyleMedium%d",
233 table_obj->style_type_number);
234 LXW_PUSH_ATTRIBUTES_STR("name", name);
235 }
236 else if (table_obj->style_type == LXW_TABLE_STYLE_TYPE_DARK) {
237 lxw_snprintf(name, LXW_ATTR_32, "TableStyleDark%d",
238 table_obj->style_type_number);
239 LXW_PUSH_ATTRIBUTES_STR("name", name);
240 }
241 else {
242 LXW_PUSH_ATTRIBUTES_STR("name", "TableStyleMedium9");
243 }
244
245 if (table_obj->first_column)
246 LXW_PUSH_ATTRIBUTES_STR("showFirstColumn", "1");
247 else
248 LXW_PUSH_ATTRIBUTES_STR("showFirstColumn", "0");
249
250 if (table_obj->last_column)
251 LXW_PUSH_ATTRIBUTES_STR("showLastColumn", "1");
252 else
253 LXW_PUSH_ATTRIBUTES_STR("showLastColumn", "0");
254
255 if (table_obj->no_banded_rows)
256 LXW_PUSH_ATTRIBUTES_STR("showRowStripes", "0");
257 else
258 LXW_PUSH_ATTRIBUTES_STR("showRowStripes", "1");
259
260 if (table_obj->banded_columns)
261 LXW_PUSH_ATTRIBUTES_STR("showColumnStripes", "1");
262 else
263 LXW_PUSH_ATTRIBUTES_STR("showColumnStripes", "0");
264
265 lxw_xml_empty_tag(self->file, "tableStyleInfo", &attributes);
266
267 LXW_FREE_ATTRIBUTES();
268 }
269
270 /*****************************************************************************
271 *
272 * XML file assembly functions.
273 *
274 ****************************************************************************/
275
276 /*
277 * Assemble and write the XML file.
278 */
279 void
lxw_table_assemble_xml_file(lxw_table * self)280 lxw_table_assemble_xml_file(lxw_table *self)
281 {
282 /* Write the XML declaration. */
283 _table_xml_declaration(self);
284
285 /* Write the table element. */
286 _table_write_table(self);
287
288 /* Write the autoFilter element. */
289 _table_write_auto_filter(self);
290
291 /* Write the tableColumns element. */
292 _table_write_table_columns(self);
293
294 /* Write the tableStyleInfo element. */
295 _table_write_table_style_info(self);
296
297 lxw_xml_end_tag(self->file, "table");
298 }
299
300 /*****************************************************************************
301 *
302 * Public functions.
303 *
304 ****************************************************************************/
305