diff --git a/src/components/gui/export/export-result-button.tsx b/src/components/gui/export/export-result-button.tsx
index 6ab4388f..64a245f0 100644
--- a/src/components/gui/export/export-result-button.tsx
+++ b/src/components/gui/export/export-result-button.tsx
@@ -17,7 +17,15 @@ import OptimizeTableState, {
} from "../table-optimized/optimize-table-state";
export type ExportTarget = "clipboard" | "file";
-export type ExportFormat = "csv" | "delimited" | "json" | "sql" | "xlsx";
+export type ExportFormat =
+ | "csv"
+ | "delimited"
+ | "json"
+ | "sql"
+ | "xlsx"
+ | "xml"
+ | "md"
+ | "tsv";
export type ExportSelection =
| "complete"
| "selected_row"
@@ -319,6 +327,33 @@ export default function ExportResultButton({
Excel
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/lib/export-helper.ts b/src/lib/export-helper.ts
index fbb1b0e5..8b11605f 100644
--- a/src/lib/export-helper.ts
+++ b/src/lib/export-helper.ts
@@ -187,6 +187,81 @@ export function exportDataAsDelimitedText(
return content;
}
+export function exportRowsToXml(
+ headers: string[],
+ records: unknown[][],
+ exportTarget?: ExportTarget
+): string {
+ const escapeXml = (unsafe: string) =>
+ unsafe
+ .replace(/&/g, "&")
+ .replace(//g, ">")
+ .replace(/"/g, """)
+ .replace(/'/g, "'");
+
+ let xml = '\n\n';
+
+ for (const record of records) {
+ xml += " \n";
+ for (let i = 0; i < headers.length; i++) {
+ const header = escapeXml(headers[i]);
+ const value = record[i] != null ? escapeXml(String(record[i])) : "";
+ xml += ` <${header}>${value}${header}>\n`;
+ }
+ xml += "
\n";
+ }
+
+ xml += "";
+
+ if (exportTarget === "clipboard") {
+ copyToClipboard(xml);
+ return "";
+ }
+
+ return xml;
+}
+
+export function exportToMarkdown(
+ headers: string[],
+ records: unknown[][],
+ exportTarget?: ExportTarget
+) {
+ let result = `| ${headers.join(" | ")} | \n`;
+ result += `| ${headers.map(() => "---").join(" | ")} | \n`;
+
+ for (const record of records) {
+ const row = record.map((value) => `| ${value} `).join(" ") + " |";
+ result += row + "\n";
+ }
+
+ if (exportTarget === "clipboard") {
+ copyToClipboard(result);
+ return "";
+ }
+
+ return result;
+}
+
+export function exportToTSV(
+ headers: string[],
+ records: unknown[][],
+ exportTarget?: ExportTarget
+) {
+ let result = `${headers.join("\t")}\n`;
+ for (const record of records) {
+ const row = record.join("\t");
+ result += row + "\n";
+ }
+
+ if (exportTarget === "clipboard") {
+ copyToClipboard(result);
+ return "";
+ }
+
+ return result;
+}
+
export function getFormatHandlers(
data: OptimizeTableState,
exportTarget: ExportTarget,
@@ -278,6 +353,9 @@ export function getFormatHandlers(
exportTarget,
exportOptions?.nullValue || "NULL"
),
+ xml: () => exportRowsToXml(headers, records, exportTarget),
+ md: () => exportToMarkdown(headers, records, exportTarget),
+ tsv: () => exportToTSV(headers, records, exportTarget),
};
}
@@ -310,6 +388,14 @@ export async function exportTableData(
exportTarget: ExportTarget,
options?: ExportOptions
): Promise {
+ console.log(
+ "Exporting",
+ schemaName,
+ tableName,
+ format,
+ exportTarget,
+ options
+ );
const result = await databaseDriver.query(
`SELECT * FROM ${databaseDriver.escapeId(schemaName)}.${databaseDriver.escapeId(tableName)}`
);
@@ -338,6 +424,9 @@ export async function exportTableData(
options?.encloser || '"',
exportTarget
),
+ xml: () => exportRowsToXml(headers, records, exportTarget),
+ md: () => exportToMarkdown(headers, records, exportTarget),
+ tsv: () => exportToTSV(headers, records, exportTarget),
};
const handler = formatHandlers[format];