///|
/// 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("")
  }
  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("
") html_export_write_escaped(out, header) 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") } out.write_string("

Column Profile

\n") out.write_string(" \n") out.write_string( " \n", ) for profile in profiles { out.write_string(" \n") } out.write_string("
ColumnTypeEmptyNon-emptyUniqueMinMaxAverage
") 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.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 => () } }