+}
+
+static void
+write_footnotes (struct odt_driver *odt,
+ const struct pivot_table *pt,
+ const size_t *footnote_indexes,
+ size_t n_footnotes)
+{
+ for (size_t i = 0; i < n_footnotes; i++)
+ {
+ const struct pivot_footnote *f = pt->footnotes[footnote_indexes[i]];
+ if (f->show)
+ {
+ xmlTextWriterStartElement (odt->content_wtr, _xml("text:span"));
+ xmlTextWriterWriteAttribute (odt->content_wtr,
+ _xml("text:style-name"),
+ _xml("superscript"));
+ char *s = pivot_footnote_marker_string (f, pt);
+ write_xml_with_line_breaks (odt, s);
+ free (s);
+ xmlTextWriterEndElement (odt->content_wtr);
+ }
+ }
+}
+
+static void
+write_table_item_cell (struct odt_driver *odt,
+ const struct pivot_table *pt,
+ const struct table_cell *cell)
+{
+ struct string body = DS_EMPTY_INITIALIZER;
+ pivot_value_format_body (cell->value, pt, &body);
+ xmlTextWriterWriteString (odt->content_wtr, _xml (ds_cstr (&body)));
+ ds_destroy (&body);
+
+ const struct pivot_value_ex *ex = pivot_value_ex (cell->value);
+ write_footnotes (odt, pt, ex->footnote_indexes, ex->n_footnotes);
+}
+
+static void
+write_table__ (struct odt_driver *odt, const struct pivot_table *pt,
+ const struct table *t)
+{
+ if (t)
+ {
+ for (size_t y = 0; y < t->n[V]; y++)
+ {
+ xmlTextWriterStartElement (odt->content_wtr, _xml("text:h"));
+ xmlTextWriterWriteFormatAttribute (odt->content_wtr,
+ _xml("text:outline-level"), "%d", 2);
+
+ struct table_cell cell;
+ table_get_cell (t, 0, y, &cell);
+ write_table_item_cell (odt, pt, &cell);
+
+ xmlTextWriterEndElement (odt->content_wtr);
+ }
+ }
+}
+
+static void
+write_table_layer (struct odt_driver *odt, const struct pivot_table *pt,
+ const size_t *layer_indexes)
+{
+ struct table *title, *layers, *body, *caption, *footnotes;
+ pivot_output (pt, layer_indexes, true, &title, &layers, &body,
+ &caption, &footnotes, NULL, NULL);
+
+ /* Write a heading for the table */
+ write_table__ (odt, pt, title);
+ write_table__ (odt, pt, layers);