///|
/// Export a table as a compact HTML table.
pub fn table_to_html(table : CsvTable) -> String {
let out = StringBuilder()
out.write_string("\n")
out.write_string(" \n")
out.write_string(" ")
for header in table.headers {
out.write_string("")
html_export_write_escaped(out, header)
out.write_string(" ")
}
out.write_string(" \n")
out.write_string(" \n")
out.write_string(" \n")
for row in table.rows {
out.write_string(" ")
for i in 0..")
html_export_write_escaped(out, html_export_cell_at(row, i))
out.write_string("")
}
out.write_string(" \n")
}
out.write_string(" \n")
out.write_string("
")
out.to_string()
}
///|
/// Export a profile report as Markdown, suitable for README or issue comments.
pub fn profile_report_markdown(table : CsvTable) -> String {
let profiles = profile_table(table)
let out = StringBuilder()
out.write_string("# Data Profile\n\n")
out.write_string("- Rows: \{table.rows.length()}\n")
out.write_string("- Columns: \{table.headers.length()}\n\n")
out.write_string(
"| column | type | empty | non_empty | unique | min | max | average |\n",
)
out.write_string("| --- | --- | ---: | ---: | ---: | --- | --- | --- |\n")
for profile in profiles {
out.write_string("| ")
html_export_write_markdown_cell(out, profile.name)
out.write_string(" | ")
html_export_write_markdown_cell(out, inferred_type_name(profile.inferred))
out.write_string(
" | \{profile.empty} | \{profile.non_empty} | \{profile.unique} | ",
)
html_export_write_optional_double(out, profile.min)
out.write_string(" | ")
html_export_write_optional_double(out, profile.max)
out.write_string(" | ")
html_export_write_optional_double(out, profile.average)
out.write_string(" |\n")
}
out.to_string()
}
///|
/// Export validation errors as a Markdown list.
pub fn validation_errors_to_markdown(
errors : Array[CsvValidationError],
) -> String {
if errors.length() == 0 {
"No validation errors."
} else {
let out = StringBuilder()
out.write_string("# Validation Errors\n\n")
for error in errors {
out.write_string(
"- Row \{error.row}, column `\{error.column}`: \{error.message}\n",
)
}
out.to_string()
}
}
///|
/// Export a full quality report as HTML.
pub fn quality_report_html(
table : CsvTable,
errors : Array[CsvValidationError],
) -> String {
let profiles = profile_table(table)
let out = StringBuilder()
out.write_string("\n\n\n")
out.write_string(" \n")
out.write_string(" CSV Quality Report \n")
out.write_string(" \n")
out.write_string("\n\n")
out.write_string(" CSV Quality Report
\n")
out.write_string(
" Rows: \{table.rows.length()} · Columns: \{table.headers.length()}
\n",
)
if errors.length() == 0 {
out.write_string(" No validation errors.
\n")
} else {
out.write_string(" Validation Errors
\n")
out.write_string(" \n")
for error in errors {
out.write_string(" - Row \{error.row}, ")
html_export_write_escaped(out, error.column)
out.write_string(": ")
html_export_write_escaped(out, error.message)
out.write_string("
\n")
}
out.write_string("
\n")
}
out.write_string(" Column Profile
\n")
out.write_string(" \n")
out.write_string(
" Column Type Empty Non-empty Unique Min Max Average \n",
)
for profile in profiles {
out.write_string(" ")
html_export_write_escaped(out, profile.name)
out.write_string(" ")
html_export_write_escaped(out, inferred_type_name(profile.inferred))
out.write_string(
" \{profile.empty} \{profile.non_empty} \{profile.unique} ",
)
html_export_write_optional_double(out, profile.min)
out.write_string(" ")
html_export_write_optional_double(out, profile.max)
out.write_string(" ")
html_export_write_optional_double(out, profile.average)
out.write_string(" \n")
}
out.write_string("
\n")
out.write_string("\n")
out.to_string()
}
///|
fn html_export_cell_at(row : Array[String], index : Int) -> String {
if index >= 0 && index < row.length() {
row[index]
} else {
""
}
}
///|
fn html_export_write_escaped(out : StringBuilder, value : String) -> Unit {
for ch in value.iter() {
if ch == '&' {
out.write_string("&")
} else if ch == '<' {
out.write_string("<")
} else if ch == '>' {
out.write_string(">")
} else if ch == '"' {
out.write_string(""")
} else if ch == '\'' {
out.write_string("'")
} else {
out.write_char(ch)
}
}
}
///|
fn html_export_write_markdown_cell(out : StringBuilder, value : String) -> Unit {
for ch in value.iter() {
if ch == '|' {
out.write_string("\\|")
} else if ch == '\n' || ch == '\r' {
out.write_char(' ')
} else {
out.write_char(ch)
}
}
}
///|
fn html_export_write_optional_double(
out : StringBuilder,
value : Double?,
) -> Unit {
match value {
Some(number) => out.write_string(number.to_string())
None => ()
}
}