CSV to HTML translation: Difference between revisions
→{{header|AutoHotkey}}: AutoHotkey example added |
m →{{header|AutoHotkey}}: fixed amp's |
||
Line 225: | Line 225: | ||
<tr><td>Character</td><td>Speech</td></tr> |
<tr><td>Character</td><td>Speech</td></tr> |
||
<tr><td>The multitude</td><td>The messiah! Show us the messiah!</td></tr> |
<tr><td>The multitude</td><td>The messiah! Show us the messiah!</td></tr> |
||
<tr><td>Brians mother</td><td>&lt;angry&gt;Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry></td></tr> |
<tr><td>Brians mother</td><td>&lt;angry&gt;Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!&lt;/angry&gt;</td></tr> |
||
<tr><td>The multitude</td><td>Who are you?</td></tr> |
<tr><td>The multitude</td><td>Who are you?</td></tr> |
||
<tr><td>Brians mother</td><td>I'm his mother; that's who!</td></tr> |
<tr><td>Brians mother</td><td>I'm his mother; that's who!</td></tr> |
Revision as of 21:56, 9 September 2011
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
Consider a simplified CSV format where all rows are separated by a newline and all columns are separated by commas. No commas are allowed as field data, but the data may contain other characters and character sequences that would normally be escaped when converted to HTML
The task is to create a function that takes a string representation of the CSV data and returns a text string of an HTML table representing the CSV data. Use the following data as the CSV text to convert, and show your output.
- Character,Speech
- The multitude,The messiah! Show us the messiah!
- Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>
- The multitude,Who are you?
- Brians mother,I'm his mother; that's who!
- The multitude,Behold his mother! Behold his mother!
For extra credit, optionally allow special formatting for the first row of the table as if it is the tables header row.
Ada
csv2html.adb: <lang Ada>with Ada.Strings.Fixed; with Ada.Text_IO; with Templates_Parser;
procedure Csv2Html is
use type Templates_Parser.Vector_Tag;
Chars : Templates_Parser.Vector_Tag; Speeches : Templates_Parser.Vector_Tag;
CSV_File : Ada.Text_IO.File_Type;
begin
-- read the csv data Ada.Text_IO.Open (File => CSV_File, Mode => Ada.Text_IO.In_File, Name => "data.csv");
-- fill the tags while not Ada.Text_IO.End_Of_File (CSV_File) loop declare Whole_Line : String := Ada.Text_IO.Get_Line (CSV_File); Comma_Pos : Natural := Ada.Strings.Fixed.Index (Whole_Line, ","); begin Chars := Chars & Whole_Line (Whole_Line'First .. Comma_Pos - 1); Speeches := Speeches & Whole_Line (Comma_Pos + 1 .. Whole_Line'Last); end; end loop;
Ada.Text_IO.Close (CSV_File);
-- build translation table and output html declare Translations : constant Templates_Parser.Translate_Table := (1 => Templates_Parser.Assoc ("CHAR", Chars), 2 => Templates_Parser.Assoc ("SPEECH", Speeches)); begin Ada.Text_IO.Put_Line (Templates_Parser.Parse ("table.tmplt", Translations)); end;
end Csv2Html;</lang>
table.tmplt:
<lang html5>
@@TABLE@@ @@END_TABLE@@@_WEB_ESCAPE:CHAR_@ | @_WEB_ESCAPE:SPEECH_@ |
</lang>
Output:
<lang html5>
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
ALGOL 68
<lang algol68>#!/usr/local/bin/a68g --script #
[6]STRING rows := []STRING(
"Character,Speech", "The multitude,The messiah! Show us the messiah!", "Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>", "The multitude,Who are you?", "Brians mother,I'm his mother; that's who!", "The multitude,Behold his mother! Behold his mother!"
);
[max abs char]STRING encoded; FOR i TO UPB encoded DO encoded[i]:=REPR i OD;
- encoded[ABS""""] := """; optional #
encoded[ABS "&"] := "&"; encoded[ABS "<"] := "<";
- encoded[ABS ">"] := ">"; optional #
OP ENCODE = (STRING s)STRING: (
STRING out := ""; FOR i TO UPB s DO out+:= encoded[ABS s[i]] OD; out
);
PROC head = (STRING title)VOID: (
printf(( $"<HEAD>"l$, $"<TITLE>"g"</TITLE>"l$, title, $"<STYLE type=""text/css"">"l$, $"TD {background-color:#ddddff; }"l$, $"thead TD {background-color:#ddffdd; text-align:center; }"l$, $"</STYLE>"l$, $"</HEAD>"l$ ))
);
- define HTML tags using Algol68's "reverent" block structuring #
PROC html = VOID: print(("<HTML>", new line)),
body = VOID: print(("<BODY>", new line)),
table = VOID: print(("
", new line)), table row = VOID: print(("")), th = (STRING s)VOID: printf(($""$, s)), td = (STRING s)VOID: printf(($""$, s)), elbat row = VOID: print(("", new line)), elbat = VOID: print((""g" | "g" |
---|
", new line)),
ydob = VOID: print(("</BODY>", new line)), lmth = VOID: print(("</HTML>", new line));
FILE row input; STRING row; CHAR ifs = ","; associate(row input, row); make term(row input, ifs);
html;
head("CSV to HTML translation - Extra Credit"); body; table; FOR nr TO UPB rows DO row := rows[nr]; table row; on logical file end(row input, (REF FILE row input)BOOL: row end); FOR nf DO STRING field; get(row input,field); (nr=1|th|td)(ENCODE field); get(row input, space) OD; row end: reset(row input); elbat row OD; elbat; ydob;
lmth</lang> Output:<lang html5><HTML> <HEAD> <TITLE>CSV to HTML translation - Extra Credit</TITLE> <STYLE type="text/css"> TD {background-color:#ddddff; } thead TD {background-color:#ddffdd; text-align:center; } </STYLE> </HEAD> <BODY>
Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</BODY> </HTML></lang>
AutoHotkey
Very basic implementation <lang AutoHotkey>CSVData = ( Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother! )
TableData := "
" Loop Parse, CSVData,`n { TableData .= "`n " Loop Parse, A_LoopField, CSV TableData .= "" TableData .= "" } TableData .= "`n" HTMLEncode(A_LoopField) " |
"
HTMLEncode(str){
static rep := "&<lt;>gt;""quot" Loop Parse, rep,; StringReplace, str, str, % SubStr(A_LoopField, 1, 1), % "&" . SubStr(A_LoopField, 2) . ";", All return str
} MsgBox % clipboard := TableData</lang> Output:
<table> <tr><td>Character</td><td>Speech</td></tr> <tr><td>The multitude</td><td>The messiah! Show us the messiah!</td></tr> <tr><td>Brians mother</td><td><angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry></td></tr> <tr><td>The multitude</td><td>Who are you?</td></tr> <tr><td>Brians mother</td><td>I'm his mother; that's who!</td></tr> <tr><td>The multitude</td><td>Behold his mother! Behold his mother!</td></tr> </table>
(note the output has been modified slightly since this webpage is html.)
C
This produces a full bare html (tidy gives 1 warning) with styles embedded but not "inlined"; it does not escape characters that does not need to be escaped (provided that the correct encoding matching the encoding of the input is given; currently hard-endoded UTF-8). <lang c>#include <stdio.h>
- include <stddef.h>
- include <stdlib.h>
- include <string.h>
- define BUF_LEN 12
void html_min_header(const char *enc, const char *title) {
printf("<html><head><title>%s</title>"
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">" "<style type=\"text/css\">" "</style></head><body>", title, enc); }
void html_min_footer(void) {
printf("</body></html>");
}
void escape_html(char *o, int c) {
static const char *specials = "<>&"; static const char *map[] = { "<", ">", "&"}; ptrdiff_t pos; char *p; if ( (p = strchr(specials, c)) != NULL ) { pos = p - specials; if (o != NULL) strcpy(o, map[pos]); } else { o[0] = c; o[1] = '\0'; }
}
void add_column(const char *type, int c) {
char buf[BUF_LEN];
if ( c == '\n' ) return;
printf("<%s>", type); for(; c != EOF && c != '\n'; c = getchar()) { if (c == ',') { printf("</%s><%s>", type, type); continue; } escape_html(buf, c); printf("%s", buf); } printf("</%s>", type);
}
enum mode {
FIRST = 1, NEXT
}; int main(int argc, char **argv) {
int c; enum mode status = FIRST;
html_min_header("utf-8", "CSV converted into HTML");
printf("
"); while( (c = getchar()) != EOF ) { printf(""); switch(status) { case FIRST: add_column("th", c); status = NEXT; break; case NEXT: default: add_column("td", c); break; } printf(""); } printf("");
html_min_footer();
return EXIT_SUCCESS;
}</lang> Output:
<lang html5><html><head><title>CSV converted into HTML</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><style type="text/css"></style></head><body>
Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</body></html></lang>
C++
<lang cpp>#include <string>
- include <boost/regex.hpp>
- include <iostream>
std::string csvToHTML( const std::string & ) ;
int main( ) {
std::string text = "Character,Speech\n" "The multitude,The messiah! Show us the messiah!\n"
"Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>\n" "The multitude,Who are you?\n" "Brians mother,I'm his mother; that's who!\n" "The multitude,Behold his mother! Behold his mother!\n" ;
std::cout << csvToHTML( text ) ; return 0 ;
}
std::string csvToHTML( const std::string & csvtext ) {
//the order of the regexes and the replacements is decisive! std::string regexes[ 5 ] = { "<" , ">" , "^(.+?)\\b" , "," , "\n" } ;
const char* replacements [ 5 ] = { "<" , ">" , " $1" , "", "\n" } ;
boost::regex e1( regexes[ 0 ] ) ; std::string tabletext = boost::regex_replace( csvtext , e1 , replacements[ 0 ] , boost::match_default | boost::format_all ) ; for ( int i = 1 ; i < 5 ; i++ ) { e1.assign( regexes[ i ] ) ; tabletext = boost::regex_replace( tabletext , e1 , replacements[ i ] , boost::match_default | boost::format_all ) ; }
tabletext = std::string( "
\n" ) + tabletext ; tabletext.append( "\n" ) ;
return tabletext ;
}</lang> Output: <lang html5>
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
C#
<lang C sharp> using System; using System.Collections.Generic; using System.Linq; using System.Net;
class Program { private static string ConvertCsvToHtmlTable(string csvText) { //split the CSV, assume no commas or line breaks in text List<List<string>> splitString = new List<List<string>>(); List<string> lineSplit = csvText.Split('\n').ToList(); foreach (string line in lineSplit) { splitString.Add(line.Split(',').ToList()); }
//encode text safely, and create table
string tableResult = "
"; foreach(List<string> splitLine in splitString) { tableResult += ""; foreach(string splitText in splitLine) { tableResult += "";}tableResult += ""; } tableResult += "
" + WebUtility.HtmlEncode(splitText) + " |
";
return tableResult; } }
</lang>
Output when using the text suggested: <lang html5>
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
CoffeeScript
<lang coffeescript>String::__defineGetter__ 'escaped', () -> this.replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') // rosettacode doesn't like "
text = Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!
lines = (line.split ',' for line in text.split /[\n\r]+/g)
header = lines.shift()
console.log """
<thead></thead> <tbody> """
for line in lines [character, speech] = line console.log """
"""
console.log """ </tbody>
#{header[0]} | #{header[1]} | #{character} | #{speech.escaped} |
---|
"""</lang>
Output:
<lang html5>
<thead></thead> <tbody>
</tbody>
Character | Speech | The multitude | The messiah! Show us the messiah! | Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> | The multitude | Who are you? | Brians mother | I'm his mother; that's who! | The multitude | Behold his mother! Behold his mother! |
---|
</lang>
Delphi
This solution solves both the basic and extra credit tasks.
<lang Delphi>
program csv2html;
{$APPTYPE CONSOLE}
uses
SysUtils, Classes;
const
// Carriage Return/Line Feed CRLF = #13#10;
// The CSV data csvData = 'Character,Speech'+CRLF+ 'The multitude,The messiah! Show us the messiah!'+CRLF+ 'Brians mother,<angry>Now you listen here! Hes not the messiah; hes a very naughty boy! Now go away!</angry>'+CRLF+ 'The multitude,Who are you?'+CRLF+ 'Brians mother,Im his mother; thats who!'+CRLF+ 'The multitude,Behold his mother! Behold his mother!';
// HTML header htmlHead = '<!DOCTYPE html'+CRLF+ 'PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'+CRLF+ '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'+CRLF+ '<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">'+CRLF+ '<head>'+CRLF+ '<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />'+CRLF+ '<title>CSV-to-HTML Conversion</title>'+CRLF+ '<style type="text/css">'+CRLF+ 'body {font-family:verdana,helvetica,sans-serif;font-size:100%}'+CRLF+ 'table {width:70%;border:0;font-size:80%;margin:auto}'+CRLF+ 'th,td {padding:4px}'+CRLF+ 'th {text-align:left;background-color:#eee}'+CRLF+ 'th.c {width:15%}'+CRLF+ 'td.c {width:15%}'+CRLF+ '</style>'+CRLF+ '</head>'+CRLF+ '<body>'+CRLF;
// HTML footer htmlFoot = '</body>'+CRLF+ '</html>';
{ Function to split a string into a list using a given delimiter }
procedure SplitString(S, Delim: string; Rslt: TStrings);
var
i: integer; fld: string;
begin
fld := ;
for i := Length(S) downto 1 do begin if S[i] = Delim then begin Rslt.Insert(0,fld); fld := ; end else fld := S[i]+fld; end;
if (fld <> ) then Rslt.Insert(0,fld);
end;
{ Simple CSV parser with option to specify that the first row is a header row }
procedure ParseCSV(const csvIn: string; htmlOut: TStrings; FirstRowIsHeader: Boolean = True);
const
rowstart = ''; rowend = ''; cellendstart = ''; hcellendstart = ''; hrowstart = ''; hrowend = ''; var tmp,pieces: TStrings; i: Integer; begin // HTML header htmlOut.Text := htmlHead + CRLF + CRLF; // Start the HTML table htmlOut.Text := htmlOut.Text + '
' + CRLF; // Create stringlist tmp := TStringList.Create; try // Assign CSV data to stringlist and fix occurences of '<' and '>' tmp.Text := StringReplace(csvIn,'<','<',[rfReplaceAll]); tmp.Text := StringReplace(tmp.Text,'>','>',[rfReplaceAll]); // Create stringlist to hold the parts of the split data pieces := TStringList.Create; try // Loop through the CSV rows for i := 0 to Pred(tmp.Count) do begin // Split the current row SplitString(tmp[i],',',pieces); // Check if first row and FirstRowIsHeader flag set if (i = 0) and FirstRowIsHeader then // Render HTML htmlOut.Text := htmlOut.Text + hrowstart + pieces[0] + hcellendstart + pieces[1] + hrowend + CRLF else htmlOut.Text := htmlOut.Text + rowstart + pieces[0] + cellendstart + pieces[1] + rowend + CRLF; end; // Finish the HTML table and end the HTML page htmlOut.Text := htmlOut.Text + '' + CRLF + htmlFoot;
finally pieces.Free; end;
finally tmp.Free; end;
end;
var
HTML: TStrings;
begin
// Create stringlist to hold HTML output HTML := TStringList.Create; try Writeln('Basic:'); Writeln();
// Load and parse the CSV data ParseCSV(csvData,HTML,False);
// Output the HTML to the console Writeln(HTML.Text);
// Save the HTML to a file (in application's folder) HTML.SaveToFile('csv2html_basic.html');
Writeln(); Writeln('====================================='); Writeln();
HTML.Clear;
Writeln('Extra Credit:'); Writeln();
// Load and parse the CSV data ParseCSV(csvData,HTML,True);
// Output the HTML to the console Writeln(HTML.Text);
// Save the HTML to a file (in application's folder) HTML.SaveToFile('csv2html_extra.html'); Writeln(); Writeln('=====================================');
finally HTML.Free; end;
// Keep console window open Readln;
end.
</lang>
Basic output:
<lang html5>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
<title>CSV-to-HTML Conversion</title>
<style type="text/css">
body {font-family:verdana,helvetica,sans-serif;font-size:100%}
table {width:70%;border:0;font-size:80%;margin:auto}
th,td {padding:4px}
th {text-align:left;background-color:#eee}
th.c {width:15%}
td.c {width:15%}
</style>
</head>
<body>
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</body> </html> </lang>
Extra credit output: <lang html5> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> <head> <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" /> <title>CSV-to-HTML Conversion</title> <style type="text/css"> body {font-family:verdana,helvetica,sans-serif;font-size:100%} table {width:70%;border:0;font-size:80%;margin:auto} th,td {padding:4px} th {text-align:left;background-color:#eee} th.c {width:15%} td.c {width:15%} </style> </head> <body>
Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</body> </html> </lang>
Go
Minimalist version satisfies basic task requirements: <lang go>package main
import (
"bytes" "fmt" "strings" "template"
)
func main() {
fmt.Print(csvToHtml(`Character,Speech
The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!`)) }
func csvToHtml(csv string) string {
lines := strings.Split(csv, "\n") data := make([][]string, len(lines)) for i, l := range lines { data[i] = strings.Split(l, ",") } var b bytes.Buffer
template.Must(new(template.Template).Parse(`
Template:Range .Template:Range .Template:EndTemplate:EndTemplate:Html . |
`)).Execute(&b, data)
return b.String()
}</lang> Extra credit version interprets "optionally" with a command line option. When running the compiled program, a command line option of -h does the special formatting for the heading line. Also different in this version is some error checking, a few things pulled apart and given names for the purpose of readability, and use of a template set to show how templates can be composed of common pieces. <lang go>package main
import (
"bytes" "flag" "fmt" "os" "strings" "template"
)
const csv = `Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!`
func main() {
headings := flag.Bool("h", false, "format first row as column headings") flag.Parse() if html, err := csvToHtml(csv, *headings); err == nil { fmt.Println(html) } else { fmt.Println(err) }
}
type line struct {
Character, Speech string
}
type script struct {
Headings line Body []line
}
func csvToHtml(csv string, specialHeadings bool) (string, os.Error) {
lines := strings.Split(csv, "\n") if len(lines) == 0 { return "", os.NewError("no data") } var s script if specialHeadings { hl := strings.Split(lines[0], ",") if len(hl) != 2 { return "", fmt.Errorf( "%d column headings found. 2 required", len(hl)) } s.Headings = line{hl[0], hl[1]} lines = lines[1:] } s.Body = make([]line, len(lines)) for i, l := range lines { bl := strings.Split(l, ",") if len(bl) != 2 { return "", fmt.Errorf( "%d csv items found in line %d of script. 2 required", len(bl), i+1) } s.Body[i] = line{bl[0], bl[1]} } set := template.SetMust(new(template.Set).Parse(tables)) tmpl := "tableNoHeadings" if specialHeadings { tmpl = "tableWithHeadings" } var b bytes.Buffer err := set.Execute(&b, tmpl, s) return b.String(), err
}
var tables = `
Template:Define "body"Template:Range . Template:Html .CharacterTemplate:Html .Speech
Template:Define "tableNoHeadings"
Template:Template "body" .BodyTemplate:Define "tableWithHeadings"
Template:Template "body" .BodyTemplate:Html .Headings.Character | Template:Html .Headings.Speech |
---|
Template:End`</lang> Output of the extra credit version, with and without the -h option: <lang html5> > csv2html -h
Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
> csv2html
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
Groovy
Solution #1: Nested GStrings
Brute force solution using nested GStrings. It solves both the basic and extra credit tasks. <lang groovy>def formatCell = { cell ->
"${cell.replaceAll('&','&').replaceAll('<','<')}"
}
def formatRow = { row ->
"""${row.split(',').collect { cell -> formatCell(cell) }.join()} """ } def formatTable = { csv, header=false -> def rows = csv.split('\n').collect { row -> formatRow(row) } header \ ? """
<thead> ${rows[0]}</thead> <tbody> ${rows[1..-1].join()}</tbody>""" \
: """${rows.join()}
""" }
def formatPage = { title, csv, header=false -> """<html> <head> <title>${title}</title> <style type="text/css"> td {background-color:#ddddff; } thead td {background-color:#ddffdd; text-align:center; } </style> </head> <body>${formatTable(csv, header)}</body> </html>""" }</lang>
Test: <lang groovy>def csv = Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!
println 'Basic:' println '-----------------------------------------' println (formatPage('Basic', csv)) println '-----------------------------------------' println() println() println 'Extra Credit:' println '-----------------------------------------' println (formatPage('Extra Credit', csv, true)) println '-----------------------------------------'</lang>
Basic output:
<head> <title>Basic</title> <style type="text/css"> td {background-color:#ddddff; } thead td {background-color:#ddffdd; text-align:center; } </style> </head> <body>
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</body>
</html></lang>
Appearance as rendered in Google Chrome.
Extra Credit output:
<head> <title>Extra Credit</title> <style type="text/css"> td {background-color:#ddddff; } thead td {background-color:#ddffdd; text-align:center; } </style> </head> <body>
<thead></thead> <tbody>
</tbody>
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</body>
</html></lang>
Appearance as rendered in Google Chrome.
Solution #2: MarkupBuilder
A much cleaner solution using the Groovy XML MarkupBuilder class. It solves both the basic and extra credit tasks. <lang groovy>import groovy.xml.MarkupBuilder
def formatRow = { doc, row ->
doc.tr { row.each { cell -> td { mkp.yield(cell) } } }
}
def formatPage = { titleString, csv, header=false ->
def writer = new StringWriter() def doc = new MarkupBuilder(writer) def rows = csv.split('\n').collect { row -> row.split(',') } doc.html { head { title (titleString) style (type:"text/css") { mkp.yield( td {background-color:#ddddff; } thead td {background-color:#ddffdd; text-align:center; } ) } } body { table { header && thead { formatRow(doc, rows[0]) } header && tbody { rows[1..-1].each { formatRow(doc, it) } } header || rows.each { formatRow(doc, it) } } } } writer.toString()
}</lang>
Test:
The interface is the same for both solutions, so we just reuse the same test as before.
Basic output:
<head> <title>Basic</title> <style type='text/css'> td {background-color:#ddddff; } thead td {background-color:#ddffdd; text-align:center; } </style> </head> <body>
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</body></html></lang>
The HTML for this solution looks superficially different than that from the GString solution, but the appearance as rendered in Google Chrome is identical.
Extra Credit output:
<head> <title>Extra Credit</title> <style type='text/css'> td {background-color:#ddddff; } thead td {background-color:#ddffdd; text-align:center; } </style> </head> <body><thead> </thead> <tbody> </tbody>
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</body></html></lang>
The HTML for this solution looks superficially different than that from the GString solution, but the appearance as rendered in Google Chrome is identical.
Haskell
Simple solution <lang haskell>splitOn :: Char -> String -> [String] splitOn _ [] = [""] splitOn delim (x:xs)
| x == delim = "" : rest | otherwise = (x:head rest):tail rest where rest = splitOn delim xs
htmlEscape :: String -> String htmlEscape = concatMap escapeChar
where escapeChar '<' = "<" escapeChar '>' = ">" escapeChar '&' = "&" escapeChar '"' = """ --" escapeChar c = [c]
toHtmlRow :: [String] -> String
toHtmlRow [] = "" toHtmlRow cols = let htmlColumns = foldr1 (++) $ map toHtmlCol cols in "\n" ++ htmlColumns ++ "" where toHtmlCol x = " " ++ htmlEscape x ++ "\n"
csvToTable :: String -> String csvToTable csv = let rows = map (splitOn ',') $ lines csv
html = unlines $ map toHtmlRow rows
in "
\n" ++ html ++ ""
main :: IO () main = interact csvToTable</lang>
- Output
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
Icon and Unicon
This solution for the extra credit works in both Icon and Unicon. The simple CSV is read from standard input and written to standard output. The presence/abscend of "-heading" in the argument list sets the variable thead to the procedure writes or a 1 (for more on this see Introduction to Icon/Unicon - Conjunction yielding different results).
<lang Icon>procedure main(arglist)
pchar := &letters ++ &digits ++ '!?;. ' # printable chars
write("
") firstHead := (!arglist == "-heading") tHead := write while row := trim(read()) do { if \firstHead then write(" <THEAD>") else tHead(" <TBODY>") writes(" ") if (\firstHead) := &null then write(" </THEAD>\n <TBODY>") tHead := 1 } write(" </TBODY>") write("")
while *row > 0 dorow ?:= ( (=",",writes(" | ")) |
writes( tab(many(pchar)) | ("&#" || ord(move(1))) ), tab(0))write(" |
")
end</lang>
Output:
<lang html5>
<THEAD></THEAD> <TBODY>
</TBODY>
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
J
Solution (extra credit) <lang j>require 'strings tables/csv' encodeHTML=: ('&';'&';'<';'<';'>';'>')&stringreplace
tag=: adverb define
'starttag endtag'=.m (,&.>/)"1 (starttag , ,&endtag) L:0 y
)
markupCells=: ('';'') tag markupHdrCells=: ('';'') tag markupRows=: ('';'',LF) tag markupTable=: (('
',LF);'') tag
makeHTMLtablefromCSV=: verb define
0 makeHTMLtablefromCSV y NB. default left arg is 0 (no header row)
t=. fixcsv encodeHTML y if. x do. t=. (markupHdrCells@{. , markupCells@}.) t else. t=. markupCells t end. ;markupTable markupRows t
)</lang>
For those interested, equivalent tacit versions of tag
and makeHTMLtablefromCSV
are:
<lang j>tag=: adverb def '[: (,&.>/)"1 m&(0&{::@[ , 1&{::@[ ,~ ]) L:0@]'
makeHTMLtablefromCSV6=: 0&$: : ([: ; markupTable@markupRows@([ markupCells`(markupHdrCells@{. , markupCells@}.)@.[ fixcsv@encodeHTML))</lang>
Example <lang j> CSVstrng=: noun define Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother! )
1 makeHTMLtablefromCSV CSVstrng</lang>
HTML output:
<lang html5>
Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
Java
Solution including simple and extra credit version
for simple solution : java -cp . Csv2Html < text.csv > simple.html
for extended solution: java -cp . Csv2Html header < text.csv > extended.html
<lang java>import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream;
class Csv2Html {
public static String escapeChars(String lineIn) { StringBuilder sb = new StringBuilder(); int lineLength = lineIn.length(); for (int i = 0; i < lineLength; i++) { char c = lineIn.charAt(i); switch (c) { case '"': sb.append("""); break; case '&': sb.append("&"); break; case '\: sb.append("'"); break; case '<': sb.append("<"); break; case '>': sb.append(">"); break; default: sb.append(c); } } return sb.toString(); }
public static void tableHeader(PrintStream ps, String[] columns) {
ps.print(""); for (int i = 0; i < columns.length; i++) { ps.print("");
ps.print(columns[i]);
ps.print(""); } ps.println(""); } public static void tableRow(PrintStream ps, String[] columns) { ps.print(""); for (int i = 0; i < columns.length; i++) { ps.print("");
ps.print(columns[i]);
ps.print(""); } ps.println(""); } public static void main(String[] args) throws Exception { boolean withTableHeader = (args.length != 0); InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); PrintStream stdout = System.out; stdout.print("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" " + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" + "<html xmlns=\"http://www.w3.org/1999/xhtml\">" + "<head><meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\"/>" + "<title>Csv2Html</title><style type=\"text/css\">" + "body{background-color:#FFF;color:#000;font-family:OpenSans,sans-serif;font-size:10px;}" + "table{border:0.2em solid #2F6FAB;border-collapse:collapse;}" + "th{border:0.15em solid #2F6FAB;padding:0.5em;background-color:#E9E9E9;}" + "td{border:0.1em solid #2F6FAB;padding:0.5em;background-color:#F9F9F9;}</style>" + "</head><body>
Csv2Html
"); stdout.println("
"); String stdinLine; boolean firstLine = true; while ((stdinLine = br.readLine()) != null) { String[] columns = escapeChars(stdinLine).split(","); if (withTableHeader == true && firstLine == true) { tableHeader(stdout, columns); firstLine = false; } else { tableRow(stdout, columns); } } stdout.println("</body></html>");
} } </lang>
Lua
<lang lua>FS = "," -- field separator
csv = [[ Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother! ]]
csv = csv:gsub( "<", "<" ) csv = csv:gsub( ">", "&gr;" )
html = { "
" } for line in string.gmatch( csv, "(.-\n)" ) do str = "" for field in string.gmatch( line, "(.-)["..FS.."?\n?]" ) do str = str .. ""endstr = str .. "" html[#html+1] = str; end html[#html+1] = "
" .. field .. " |
"
for _, line in pairs(html) do
print(line)
end</lang>
<lang html5>
Character | Speech | |
The multitude | The messiah! Show us the messiah! | |
Brians mother | <angry&gr;Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry&gr; | |
The multitude | Who are you | |
Brians mother | I'm his mother; that's who! | |
The multitude | Behold his mother! Behold his mother! |
</lang>
MATLAB
The easiest way to import csv data into MATLAB is to save it in a csv file, then import the data using the "uiimport -file" command. The result of which will be a cell array with each entry being a string delimited by the newline character.
Example: <lang MATLAB>>> data
data =
'Character,Speech' 'The multitude,The messiah! Show us the messiah!' [1x109 char] 'The multitude,Who are you?' 'Brians mother,I'm his mother; that's who!' 'The multitude,Behold his mother! Behold his mother!'</lang>
The other way is to copy and paste the data, but you will have to manually add all of the newline characters and string quotations your self. This is messy and infeasible for large amounts of data, but it is still a valid input.
Example: <lang MATLAB>>> csvData = ['Character,Speech' sprintf('\n')... 'The multitude,The messiah! Show us the messiah!' sprintf('\n')... 'Brians mother,<angry>Now you listen here! Hes not the messiah; hes a very naughty boy! Now go away!</angry>' sprintf('\n')... 'The multitude,Who are you?' sprintf('\n')... 'Brians mother,Im his mother; thats who!' sprintf('\n')... 'The multitude,Behold his mother! Behold his mother!']
csvData =
Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!</lang>
So, to be able to accept both type of inputs, the function "csvToHTHML()" tests to see if the input is a string as in example 2. If the input is a string it converts the data to a cell array of strings formatted in the exact same way MATLAB formats the first example. The output of the function will be a properly formatted HTML table, which includes the "<THEAD>" around the first row of data so that special formatting can be applied to the column titles.
<lang MATLAB>function htmlOutput = csvToHTML(csvData)
if ischar(csvData) newlineIndex = find( (csvData == char(10)) ); %find all newline characters text = cell( numel(newlineIndex),1 ); %preallocate space for processed data for i = (numel(newlineIndex):-1:1) %iterate backwards text{i} = csvData(newlineIndex(i)+1:end); csvData(newlineIndex(i):end) = []; %delete the newline and everything after it end csvData = text; clear text; end
htmlOutput = '
'; for i = (1:numel(csvData)) if i == 1 %If first entry, then include <thead> csvData{i} = [char(10) char(9) '<thead>' char(10) char(9) char(9) '' char(10) char(9) '</thead>' char(10)]; else %Otherwise, the data is a regular table row csvData{i} = [char(9) '' char(10) char(9) char(9) '' char(10) char(9) '' char(10)]; end %if %Convert each comma to its HTML equivalent for j = fliplr(find( (csvData{i} == ',') )) csvData{i} = [csvData{i}(1:j-1) '' char(10) char(9) char(9) ''... csvData{i} ' |
' csvData{i}... ' |
' csvData{i}(j+1:end)];
end %for %We could make this faster by preallocating htmlOutput but that is %more work than necessary to provide a basic solution htmlOutput = [htmlOutput csvData{i}]; end %forhtmlOutput = [htmlOutput ' |
'];
end %csvToHTML</lang>
Ouput: <lang html5>>> csvToHTML(data)
ans =
<thead></thead>Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
ML/I
This example carries out the special formatting for extra credit. This is a macro rather than a function, though, due to the nature of ML/I.
Input
<lang ML/I>MCSKIP "WITH" NL "" CSV to HTML "" assumes macros on input stream 1, terminal on stream 2 MCSKIP MT,[] MCSKIP SL WITH ~ MCINS %. "" C1=th before header output, td afterwards MCCVAR 1,2 MCSET C1=[th] "" HTML escapes MCDEF < AS [[<]] MCDEF > AS [[>]] MCDEF & AS & "" Main line processing MCDEF SL N1 OPT , N1 OR NL ALL
AS [[ ] MCSET T2=1 %L1.MCGO L2 IF T2 GR T1 [<]%C1.[>]%AT2.[</]%C1.[>] MCSET T2=T2+1 MCGO L1 %L2.[ ] MCSET C1=[td] ] [<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html> <head> <title>HTML converted from CSV</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <style type="text/css"> </style> </head> <body>
] MCSET S1=1 ~MCSET S10=2 ~MCSET S1=0 [</body> </html> ]</lang>
Output
<lang ML/I><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html> <head> <title>HTML converted from CSV</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <style type="text/css"> </style> </head>
<body>
Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</body> </html></lang>
OCaml
Simple solution
OCaml possesses a CSV module but we do not use it hereafter because the CSV data does not contain comas.
<lang ocaml>open Printf
let csv_data = "\ Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; \
he's a very naughty boy! Now go away!</angry>
The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!"
(* General HTML escape *) let escape =
let html_escapes = Str.regexp "\\([^A-Za-z0-9 ;!?'/]\\)" in let esc s = sprintf "&#%04d;" (Char.code s.[Str.group_beginning 1]) in Str.global_substitute html_escapes esc
let nl = Str.regexp "\n\r?" let coma = Str.regexp ","
let list_of_csv csv =
List.map (fun l -> Str.split coma l) (Str.split nl csv)
let print_html_table segments =
printf "
\n"; List.iter (fun line -> printf ""; List.iter (fun c -> printf "" (escape c)) line; printf "\n"; ) segments; printf "%s |
\n";
let () =
print_html_table (list_of_csv csv_data)</lang>
Sample html output:
<lang html5>
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
Extra credit solution
<lang ocaml>open Printf
let csv_data = "\ Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; \
he's a very naughty boy! Now go away!</angry>
The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!"
(* General HTML escape *) let escape =
let html_escapes = Str.regexp "\\([^A-Za-z0-9 ;!?'/]\\)" in let esc s = sprintf "&#%04d;" (Char.code s.[Str.group_beginning 1]) in Str.global_substitute html_escapes esc
let nl = Str.regexp "\n\r?" let coma = Str.regexp ","
let list_of_csv csv =
List.map (fun l -> Str.split coma l) (Str.split nl csv)
let print_html_table segments =
let print_row line =
printf ""; List.iter (fun c -> printf "%s" (escape c)) line; printf "\n" in printf "<html> <head> <style type=\"text/css\"> td {background-color:#ddddff; } thead td {background-color:#ddffdd; text-align:center; } </style> </head>"; printf "
\n<thead>"; print_row (List.hd segments); printf "</thead><tbody>\n"; List.iter print_row (List.tl segments); printf "</tbody>\n\n</html>";
let () =
print_html_table (list_of_csv csv_data)</lang>
Output: <lang html5><html>
<head> <style type="text/css"> td {background-color:#ddddff; } thead td {background-color:#ddffdd; text-align:center; } </style>
</head>
<thead></thead><tbody>
</tbody>
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</html></lang>
OpenEdge/Progress
<lang Progress (OpenEdge ABL)> FUNCTION csvToHtml RETURNS CHARACTER (
i_lhas_header AS LOGICAL, i_cinput AS CHARACTER
):
DEFINE VARIABLE coutput AS CHARACTER NO-UNDO.
DEFINE VARIABLE irow AS INTEGER NO-UNDO. DEFINE VARIABLE icolumn AS INTEGER NO-UNDO. DEFINE VARIABLE crow AS CHARACTER NO-UNDO. DEFINE VARIABLE ccell AS CHARACTER NO-UNDO.
coutput = "<html>~n~t
". DO irow = 1 TO NUM-ENTRIES( i_cinput, "~n":U ): coutput = coutput + "~n~t~t". crow = ENTRY( irow, i_cinput, "~n":U ). DO icolumn = 1 TO NUM-ENTRIES( crow ): ccell = ENTRY( icolumn, crow ). coutput = coutput + "~n~t~t~t" + IF i_lhas_header AND irow = 1 THEN "". END. coutput = coutput + "~n~t~t". END. coutput = coutput + "~n~t" ELSE " | ".
coutput = coutput + REPLACE( REPLACE( REPLACE( ccell, "&", "&" ), "<", "<" ), ">", ">" ).coutput = coutput + IF i_lhas_header AND irow = 1 THEN "" ELSE " |
---|
~n</html>".
RETURN coutput.
END FUNCTION. /* csvToHtml */
MESSAGE
csvToHtml( TRUE, "Character,Speech" + "~n" + "The multitude,The messiah! Show us the messiah!" + "~n" + "Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>" + "~n" + "The multitude,Who are you?" + "~n" + "Brians mother,I'm his mother; that's who!" + "~n" + "The multitude,Behold his mother! Behold his mother!" )
VIEW-AS ALERT-BOX.</lang> Output with header enabled <lang html><html>
Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</html></lang>
Perl
Provide the CSV data as standard input. With a command-line argument, the first row will use instead of
.
<lang perl>use HTML::Entities;
sub row {
my $elem = shift; my @cells = map {"<$elem>$_</$elem>"} split ',', shift;
print '', @cells, "\n"; } my ($first, @rest) = map {my $x = $_; chomp $x; encode_entities $x} <STDIN>; print "
\n"; row @ARGV ? 'th' : 'td', $first; row 'td', $_ foreach @rest; print "\n";</lang>
Output (with a command-line argument):
<lang html5>
Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
PicoLisp
Simple solution
<lang PicoLisp>(load "@lib/http.l")
(in "text.csv"
(
'myStyle NIL NIL (prinl) (while (split (line) ",") (<row> NIL (ht:Prin (pack (car @))) (ht:Prin (pack (cadr @)))) (prinl) ) ) )</lang> Output: <lang html5>Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
Extra credit solution
<lang PicoLisp>(load "@lib/http.l")
(in "text.csv"
(when (split (line) ",")
(
'myStyle NIL (mapcar '((S) (list NIL (pack S))) @) (prinl) (while (split (line) ",") (<row> NIL (ht:Prin (pack (car @))) (ht:Prin (pack (cadr @)))) (prinl) ) ) ) )</lang> Output: <lang html5>Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
PowerShell
Simple solution
<lang Powershell> Import-Csv -Path .\csv_html_test.csv | ConvertTo-Html -Fragment | Out-File .\csv_html_test.html </lang> Output:
<lang html5>
<colgroup> <col/> <col/> </colgroup>Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
Extra credit solution
<lang Powershell> $htmlformat = '<title>Csv to Html</title>' $htmlformat += '<style type="text/css">' $htmlformat += 'BODY{background-color:#663300;color:#FFCC00;font-family:Arial Narrow,sans-serif;font-size:17px;}' $htmlformat += 'TABLE{border-width: 3px;border-style: solid;border-color: black;border-collapse: collapse;}' $htmlformat += 'TH{border-width: 1px;padding: 3px;border-style: solid;border-color: black;background-color:#663333}' $htmlformat += 'TD{border-width: 1px;padding: 8px;border-style: solid;border-color: black;background-color:#660033}' $htmlformat += '</style>'
Import-Csv -Path .\csv_html_test.csv | ConvertTo-Html -Head $htmlformat -Body '
Csv to Html
' | Out-File .\csv_html_test.html
Invoke-Expression .\csv_html_test.html </lang> Output: <lang html5> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Csv to Html</title><style type="text/css">BODY{background-color:#663300;color:#FFCC00;font-family:Arial Narrow,sans-serif;font-size:17px;}TABLE{border-width: 3px;border-style: solid;border-color: black;border-collapse: collapse;}TH{border-width: 1px;padding: 3px;border-style: solid;border-color: black;background-color:#663333}TD{border-width: 1px;padding: 8px;border-style: solid;border-color: black;background-color:#660033}</style> </head><body>
Csv to Html
<colgroup> <col/> <col/> </colgroup>Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</body></html> </lang>
Prolog
Uses DCG. Works with SWI-Prolog.
Simple solution
<lang Prolog>csv_html :- L = "Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!",
csv_html(L, Out, []), string_to_list(Str, Out), writeln(Str).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % simple HTML % csv_html(L) -->
"
\n", csv_tr(L), "".
csv_tr([]) --> [].
csv_tr(L) -->
"\n", csv_td(L, S), "\n\n", csv_tr(S). csv_td(L, S) --> "",
csv_td_in(L, S),
"". csv_td_in([], []) --> []. csv_td_in([10|L], L) --> []. csv_td_in([44|L], S) --> "",
csv_td_in(L,S).
csv_td_in([60|T], S) --> "<", csv_td_in(T, S).
csv_td_in([62|T], S) --> ">", csv_td_in(T, S).
csv_td_in([H|T], S) --> [H], csv_td_in(T, S).
</lang> OutPut :
<lang html5>
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!></angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
Extra credit solution
<lang Prolog>csv_html_plus :- L = "Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!",
csv_html_plus(L, Out1, []), string_to_list(Str1, Out1), writeln(Str1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % HTML + % csv_html_plus(L) -->
"
\n", csv_head(L, R), csv_body(R), "".
csv_head(L, R) -->
"<THEAD>\n",
csv_head_tr(L, R),
"</THEAD>\n".
csv_head_tr(L, R) -->
"\n", csv_head_th(L, R), "\n\n". csv_head_th(L, S) --> "",
csv_head_th_in(L, S),
"". csv_head_th_in([], []) --> []. csv_head_th_in([10|L], L) --> []. csv_head_th_in([44|L], S) --> "",
csv_head_th_in(L,S).
csv_head_th_in([H|T], S) --> [H], csv_head_th_in(T, S).
csv_body(L) -->
"<TBODY>\n",
csv_body_tr(L),
"</TBODY>\n".
csv_body_tr([]) --> [].
csv_body_tr(L) -->
"\n", csv_body_td(L, S), "\n\n", csv_body_tr(S). csv_body_td(L, S) --> "",
csv_body_td_in(L, S),
"". csv_body_td_in([], []) --> []. csv_body_td_in([10|L], L) --> []. csv_body_td_in([44|L], S) --> "",
csv_body_td_in(L,S).
csv_body_td_in([60|T], S) --> "<", csv_body_td_in(T, S).
csv_body_td_in([62|T], S) --> ">", csv_body_td_in(T, S).
csv_body_td_in([H|T], S) --> [H], csv_body_td_in(T, S). </lang> Output :
<lang html5>
<THEAD> </THEAD> <TBODY> </TBODY>Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!></angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
HTML outputs rendered in firefox browser
Python
(Note: rendered versions of both outputs are shown at the foot of this section).
Simple solution
<lang python>csvtxt = \ Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!\
from cgi import escape
def _row2tr(row, attr=None):
cols = escape(row).split(',')
return ('' + .join('%s' % data for data in cols) + '') def csv2html(txt): htmltxt = '
\n' for rownum, row in enumerate(txt.split('\n')): htmlrow = _row2tr(row) htmlrow = ' <TBODY>%s</TBODY>\n' % htmlrow htmltxt += htmlrow htmltxt += '\n'
return htmltxt
htmltxt = csv2html(csvtxt) print(htmltxt)</lang>
Sample HTML output
<lang html5>
<TBODY></TBODY> <TBODY></TBODY> <TBODY></TBODY> <TBODY></TBODY> <TBODY></TBODY> <TBODY></TBODY>Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
Extra credit solution
<lang python>def _row2trextra(row, attr=None):
cols = escape(row).split(',') attr_tr = attr.get('TR', ) attr_td = attr.get('TD', ) return (('<TR%s>' % attr_tr)
+ .join('<TD%s>%s' % (attr_td, data) for data in cols) + '') def csv2htmlextra(txt, header=True, attr=None): ' attr is a dictionary mapping tags to attributes to add to that tag' attr_table = attr.get('TABLE', ) attr_thead = attr.get('THEAD', ) attr_tbody = attr.get('TBODY', ) htmltxt = '<TABLE%s>\n' % attr_table for rownum, row in enumerate(txt.split('\n')): htmlrow = _row2trextra(row, attr) rowclass = ('THEAD%s' % attr_thead) if (header and rownum == 0) else ('TBODY%s' % attr_tbody) htmlrow = ' <%s>%s</%s>\n' % (rowclass, htmlrow, rowclass[:5]) htmltxt += htmlrow htmltxt += '\n'
return htmltxt
htmltxt = csv2htmlextra(csvtxt, True,
dict(TABLE=' border="1" summary="csv2html extra program output"', THEAD=' bgcolor="yellow"', TBODY=' bgcolor="orange"' ) )
print(htmltxt)</lang>
Sample HTML output
<lang html5>
<THEAD bgcolor="yellow"></THEAD> <TBODY bgcolor="orange"></TBODY> <TBODY bgcolor="orange"></TBODY> <TBODY bgcolor="orange"></TBODY> <TBODY bgcolor="orange"></TBODY> <TBODY bgcolor="orange"></TBODY>Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
HTML outputs rendered in firefox browser
Ruby
The extra credit version has one extra line compared to the non-extra credit version. To output a header, simply add "header" to the command line:
ruby csv2html.rb header
I/O is done through standard input/output. <lang ruby>require 'cgi'
puts '
' def row2html str, wrap = "td" "" + str.split(",").map { |cell| "<#{wrap}>#{CGI.escapeHTML cell}</#{wrap}>" }.join + "" end puts row2html gets.chomp, "th" if ARGV.delete "header" while str = gets puts row2html str.chomp end puts ""</lang>Sample output:<lang html5>
Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
Tcl
<lang tcl>package require Tcl 8.5 package require csv package require html package require struct::queue
set csvData "Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!"
struct::queue rows foreach line [split $csvData "\n"] {
csv::split2queue rows $line
} html::init puts [subst {
[html::openTag table {summary="csv2html program output"}] [html::while {[rows size]} {
[html::row {*}[html::quoteFormValue [rows get]]]
}] [html::closeTag]
}]</lang>
Extra credit version: <lang tcl>package require Tcl 8.5 package require csv package require html package require struct::queue
set csvData "Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!"
html::init {
table.border 1 table.summary "csv2html program output" tr.bgcolor orange
}
- Helpers; the html package is a little primitive otherwise
proc table {contents {opts ""}} {
set out [html::openTag table $opts] append out [uplevel 1 [list subst $contents]] append out [html::closeTag]
} proc tr {list {ropt ""}} {
set out [html::openTag tr $ropt] foreach x $list {append out [html::cell "" $x td]} append out [html::closeTag]
}
- Parse the CSV data
struct::queue rows foreach line [split $csvData "\n"] {
csv::split2queue rows $line
}
- Generate the output
puts [subst {
[table {
[tr [html::quoteFormValue [rows get]] {bgcolor="yellow"}] [html::while {[rows size]} { [tr [html::quoteFormValue [rows get]]] }]
}]
}]</lang> Output:
<lang html5>
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away! </angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
TUSCRIPT
<lang tuscript> $$ MODE TUSCRIPT MODE DATA $$ csv=* Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother! $$ htmlhead=* <!DOCTYPE html system> <html> <head> <title>Life of Brian</title> <style type="text/css"> th {background-color:orange} td {background-color:yellow}
</style></head><body>
$$ BUILD X_TABLE txt2html=* << < >> > $$ MODE TUSCRIPT file="brian.html" ERROR/STOP CREATE (file,FDF-o,-std-) csv=EXCHANGE (csv,txt2html) x=SPLIT (csv,":,:",row1,row2) ACCESS html: WRITE/ERASE/RECORDS/UTF8 $file s,html WRITE html htmlhead LOOP n,td1=row1,td2=row2 IF (n==1) THEN row=CONCAT ("")ELSE
row=CONCAT ("")ENDIF WRITE html row ENDLOOP
WRITE html "",td1," | ",td2," |
---|---|
",td1," | ",td2," |
</body></html>"
ENDACCESS/PRINT html </lang>
Output (source code)
<lang html5><!DOCTYPE html system> <html> <head> <title>Life of Brian</title> <style type="text/css"> th {background-color:orange} td {background-color:yellow}
</style></head><body>
Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | <angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry> |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</body></html>
</lang>
Output (rendered)
![](http://static.miraheze.org/rosettacodewiki/thumb/7/76/Tuscript_csv2html.png/500px-Tuscript_csv2html.png)
- Programming Tasks
- Solutions by Programming Task
- Ada
- AWS
- ALGOL 68
- AutoHotkey
- C
- C++
- C sharp
- CoffeeScript
- Delphi
- Go
- Groovy
- Haskell
- Icon
- Unicon
- J
- Java
- Java examples needing attention
- Examples needing attention
- Lua
- MATLAB
- MATLAB examples needing attention
- ML/I
- OCaml
- OpenEdge/Progress
- Perl
- PicoLisp
- PowerShell
- Prolog
- Python
- Ruby
- Tcl
- Tcllib
- TUSCRIPT