CSV to HTML translation: Difference between revisions
Line 3,271:
=={{header|Nanoquery}}==
<lang nanoquery>// a method that converts a csv row into a html table row as a string
def toHtmlRow(
// loop through the values in the current csv row
for
end for
return
end def
// get the name of the csv file then open it
print "filename: "
input
open
// allocate a string to hold the table
// add the column names to the table (#0 returns column names as a record object)
// add all other rows to the table
for
end for
// close the html table
println
=={{header|NetRexx}}==
|
Revision as of 20:24, 7 November 2019
![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
- Task
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!
- Extra credit
Optionally allow special formatting for the first row of the table as if it is the tables header row
(via <thead> preferably; CSS if you must).
11l
<lang 11l>V input_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!’
print("
\n\n\n", end' ‘’)
L(c) input_csv print(S c {"\n"{" | |
"} ‘,’ {‘ | ’}
‘<’ {‘<’} ‘>’ {‘>’} ‘&’ {‘&’} E {c} }, end' ‘’)print(" |
")</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>
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.)
AutoIt
<lang AutoIt> Local $ascarray[4] = [34,38,60,62] $String = "Character,Speech" & @CRLF $String &= "The multitude,The messiah! Show us the messiah!" & @CRLF $String &= "Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>" & @CRLF $String &= "The multitude,Who are you?" & @CRLF $String &= "Brians mother,I'm his mother; that's who!" & @CRLF $String &= "The multitude,Behold his mother! Behold his mother!" For $i = 0 To UBound($ascarray) -1 $String = Stringreplace($String, chr($ascarray[$i]), "&#"&$ascarray[$i]&";") Next
$newstring = "
" & @CRLF $crlfsplit = StringSplit($String, @CRLF, 1) For $i = 1 To $crlfsplit[0] If $i = 1 Then $newstring &= "<thead>" & @CRLF $newstring &= "" & @CRLF $komsplit = StringSplit($crlfsplit[$i], ",") For $k = 1 To $komsplit[0] If $i = 1 Then $newstring &= "" & @CRLFElse
$newstring &= "" & @CRLFEndIf Next
$newstring &= "" & @CRLF If $i = 1 Then $newstring &= "</thead>" & @CRLF Next $newstring &= "" &$komsplit[$k] & " | " &$komsplit[$k] & " |
---|
"
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $newstring = ' & $newstring & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console </lang>
- Output:
<table> <thead> <tr> <th>Character</th> <th>Speech</th> </tr> </thead> <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>
ANTLR
Java
<lang java> // Create an HTML Table from comma seperated values // Nigel Galloway - June 2nd., 2013 grammar csv2html;
dialog : {System.out.println("<HTML>
");}header body+{System.out.println("</HTML>");} ; header : {System.out.println("<THEAD align=\"center\">");}row{System.out.println("</THEAD");}; body : {System.out.println("<TBODY>");}row{System.out.println("</TBODY");}; row : field ',' field '\r'? '\n'; field : Field{System.out.println("" + $Field.text.replace("<","<").replace(">",">") + "");};
Field : ~[,\n\r]+; </lang>
AWK
Includes extra credit.
File csv2html.awk
<lang awk>#!/usr/bin/awk -f
BEGIN {
FS=","
print "
" } { gsub(/</, "\\<") gsub(/>/, "\\>") gsub(/&/, "\\>") print "\t" for(f = 1; f <= NF; f++) { if(NR == 1 && header) { printf "\t\t\n", $f}else printf "\t\t\n", $f
}print "\t" } END { print "
%s | %s |
---|
"
} </lang>
$ awk -f csv2html.awk input.csv
<lang html5>
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brians mother | >lt;angry>gt;Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!>lt;/angry>gt; |
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:
$ awk -v header=1 -f csv2html.awk input.csv
<lang html5>
Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | >lt;angry>gt;Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!>lt;/angry>gt; |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</lang>
Batch File
<lang dos>::Batch Files are terrifying when it comes to string processing.
- But well, a decent implementation!
@echo off
REM Below is the CSV data to be converted. REM Exactly three colons must be put before the actual line.
- 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!
setlocal disabledelayedexpansion echo ^<table^> for /f "delims=" %%A in ('findstr "^:::" "%~f0"') do (
set "var=%%A" setlocal enabledelayedexpansion REM The next command removes the three colons... set "var=!var:~3!"
REM The following commands to the substitions per line... set "var=!var:&=&!" set "var=!var:<=<!" set "var=!var:>=>!"
set "var=!var:,=!"
echo ^<tr^>^<td^>!var!^</td^>^</tr^> endlocal
) echo ^</table^></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>
BBC BASIC
<lang bbcbasic> DATA "Character,Speech"
DATA "The multitude,The messiah! Show us the messiah!" DATA "Brian's mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>" DATA "The multitude,Who are you?" DATA "Brian's mother,I'm his mother; that's who!" DATA "The multitude,Behold his mother! Behold his mother!" DATA "***" *SPOOL CSVtoHTML.htm PRINT "<HTML>" PRINT "<HEAD>" PRINT "</HEAD>" PRINT "<BODY>"
PRINT "
" header% = TRUE REPEAT READ csv$ IF csv$ = "***" THEN EXIT REPEAT IF header% PRINT "" ELSE PRINT "" header% = FALSE UNTIL FALSE PRINT ""; ELSE PRINT " | ||
---|---|---|
";
FOR i% = 1 TO LEN(csv$) c$ = MID$(csv$, i%, 1) CASE c$ OFWHEN ",": IF header% PRINT " | "; ELSE PRINT " | ";
WHEN "<": PRINT "<"; WHEN ">": PRINT ">"; WHEN "&": PRINT "&"; OTHERWISE: PRINT c$; ENDCASE NEXT i%IF header% PRINT " |
"
PRINT "</BODY>" PRINT "</HTML>" *spool SYS "ShellExecute", @hwnd%, 0, "CSVtoHTML.htm", 0, 0, 1
</lang>
- Output:
<HTML> <HEAD> </HEAD> <BODY> <table border=1 cellpadding =10 cellspacing=0> <tr><th>Character</th><th>Speech</th></tr> <tr><td>The multitude</td><td>The messiah! Show us the messiah!</td></tr> <tr><td>Brian's 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>Brian's 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> </BODY> </HTML>
- Rendered output:
Bracmat
Extra credit solution using pattern matching
This is not the most concise solution, but it is relatively efficient. To collect the lines we use a pattern that matches a line starting from position [!p
. Each time a line is matched, p
is updated, the two found elements are collected and the pattern is forced to fail, so the pattern matcher finds the next line. The found rows are collected in reverse order, because prepending to a list is faster than appending. When all lines are read, the collected lines are reversed, interspersed with newline characters. Finally the predefined function toML is used to create HTML.
<lang bracmat>( ( CSVtoHTML
= p q Character Speech swor rows row . 0:?p & :?swor:?rows & ( @( !arg : ? ( [!p ?Character "," ?Speech \n [?q ? & !q:?p & (tr.,(th.,!Character) (th.,!Speech)) !swor : ?swor & ~ ) ) | whl ' ( !swor:%?row %?swor & !row \n !rows:?rows ) & toML $ (table.,(thead.,!swor) \n (tbody.,!rows)) ) )
& 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! " ) </lang> Output:
<lang html>
<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>
Simple solution NOT using pattern matching
Newer versions of Bracmat have the built in function vap
that splits an input string in
single characters or that splits it everywhere where a given separator character occurs. Each single character or slab of characters is
passed to a function. The values returned from this function become the elements in a list that is returned from the vap
function. For example, vap$(upp.Википедию)
"vaporizes" the word Википедию into characters and produces the list of
uppercased characters В И К И П Е Д И Ю. Instead of the name of a function we can choose to just give vap
the definition of an anonymous function, like so: vap$((=.!arg:~и|).Википедию)
. This returns a list of the characters in the word Википедию, except for the и character: В к п е д ю.
In the code below, we use vap
with a third argument, a splitting separator character. The outer call to vap
splits a text into rows. An embedded call to vap
splits each row into cell elements. This code is very efficient.
<lang Bracmat>( ( Csv2Html
= . toML $ ( table . , vap $ ( ( = .tr.,vap$((=.td.,!arg).!arg.",") ) . !arg . \n ) ) )
& 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>
Extra credit solution
<lang Bracmat>( ( Csv2Html
= . toML $ ( table . , vap $ ( (=..vap$((=.,!arg).!arg.",")) . !arg . \n ) : (.%?header) ?body & ( thead . , (tr.,map$((=.th.!arg).!header)) \n ) ( tbody . , map $ ( ( = . !arg:(.?arg) & (tr.,map$((=.td.!arg).!arg)) \n ) . !body ) ) ) )
& 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>
Output: <lang html>
<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>
Befunge
The most practical solution for Befunge was to read the CSV from stdin, so this implementation works best with command line interpreters that can accept redirected input. That said, it is still possible test with many of the GUI and online interpretors just by entering the input manually.
Note that right angle brackets are deliberately not escaped, since that is not strictly necessary for the markup to be valid.
<lang Befunge><v_>#!,#:< "
" \0 +55 v >0>::65*1+`\"~"`!*#v_4-5v > v>#^~^<v"\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( "
" < \v-1/<>">elb"
<^ >:#,_$10 |!:<>\#v_ vv"ta" v-",":\-"&":\-"<":\<>5#05#<v+ >"/"v >#v_$$$0">dt<>dt/<"vv"tr>"+<5 v"<"< >^>\#v_$$0";pma&" v>"/<>d"v5 v , < $ > \#v_$0";tl&"v v"</t"<0 > : | ^_>#!,#:<>#<0#<\#<<< >:#,_$#^_v@ $<</lang>
C<lang c>#include <stdio.h> const char *input = "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!"; int main() { const char *s; printf("\n\n\n
return 0; }</lang>
$ gcc -Wall -W -ansi -pedantic csv.c -o csv $ ./csv<lang html5>
C++<lang cpp>#include <string>
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" ) ;
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#
Simple Solution
<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>
Extra Credit Solution
<lang C sharp>using System; using System.Linq; using System.Net;
namespace CsvToHtml {
class Program { static void Main(string[] args) { string 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!";
Console.Write(ConvertCsvToHtmlTable(csv, true)); }
private static string ConvertCsvToHtmlTable(string csvText, bool formatHeaders) { var rows = (from text in csvText.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) /* Split the string by newline, * removing any empty rows. */ select text.Split(',')).ToArray(); // Split each row by comma.
string output = "
"; // Initialize the output with the value of ""; // Add closing table tag to output string.
return output; } }
}</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>
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>
Clojure
We assume the presence of a file, but the input could come from anywhere.
<lang 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! </lang>
<lang clojure> (require 'clojure.string)
(def escapes
{\< "<", \> ">", \& "&"})
(defn escape
[content] (clojure.string/escape content escapes))
(defn tr
[cells]
(format "%s" (apply str (map #(str "" (escape %) "") cells))))
- turn a seq of seq of cells into a string.
(defn to-html
[tbl]
(format "
<tbody>%s</tbody></thead>" (apply str (map tr tbl))))- Read from a string to a seq of seq of cells.
- Output:
<lang html>
</lang>
Common Lisp
<lang lisp>(defvar *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!")
(defun split-string (string delim-char)
(let ((result '())) (do* ((start 0 (1+ end))
(end (position delim-char string) (position delim-char string :start start))) ((not end) (reverse (cons (subseq string start) result)))
(push (subseq string start end) result))))
- HTML escape code modified from
(defun escape-char (char)
(case char (#\& "&") (#\< "<") (#\> ">") (t (format nil "&#~d;" (char-code char)))))
(defun escape (in)
(let ((to-escape "<>&")) (flet ((needs-escape-p (char) (find char to-escape))) (with-output-to-string (out)
(loop for start = 0 then (1+ pos) for pos = (position-if #'needs-escape-p in :start start) do (write-sequence in out :start start :end pos) when pos do (write-sequence (escape-char (char in pos)) out) while pos)))))
(defun html-row (values headerp)
(let ((tag (if headerp "th" "td"))) (with-output-to-string (out)(write-string "" out) (dolist (val values) (format out "<~A>~A</~A>" tag (escape val) tag)) (write-string "" out)))) (defun csv->html (csv) (let* ((lines (split-string csv #\Newline)) (cols (split-string (first lines) #\,)) (rows (mapcar (lambda (row) (split-string row #\,)) (rest lines)))) (with-output-to-string (html) (format 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>
CL-USER> (csv->html *csv*)
- 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>
D
<lang d>void main() {
import std.stdio;
immutable input = "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!";
"<html>\n<head><meta charset=\"utf-8\"></head>\n<body>\n\n".write;
"
\n<thead>\n \n \n</thead>\n<tbody>\n \n</tbody>\n".write;
bool theadDone = false; foreach (immutable c; input) { switch(c) { case '\n': if (theadDone) {" | |
".write;
} else {" | |
".write;
theadDone = true; } break;case ',': " | ".write; break;
case '<': "<".write; break; case '>': ">".write; break; case '&': "&".write; break; default: c.write; break; } }" |
\n\n</body></html>".write;
}</lang>
- Output:
<lang html5><html> <head><meta charset="utf-8"></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>
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>
EchoLisp
<lang scheme>
- CSV -> LISTS
(define (csv->row line) (string-split line ",")) (define (csv->table csv) (map csv->row (string-split csv "\n")))
- LISTS->HTML
(define html 'html) (define (emit-tag tag html-proc content ) (if (style tag) (push html (format "<%s style='%a'>" tag (style tag))) (push html (format "<%s>" tag ))) (html-proc content) (push html (format "</%s> " tag )))
- html procs
- 1 tag, 1 proc
(define (h-raw content) (push html (format "%s" content))) (define (h-header headers) (for ((h headers)) (emit-tag 'th h-raw h))) (define (h-row row) (for ((item row)) (emit-tag 'td h-raw item))) (define (h-table table ) (emit-tag 'tr h-header (first table)) (for ((row (rest table))) (emit-tag 'tr h-row row)))
(define (html-dump) (string-join (stack->list html) " "))
- STYLES
(style 'td "text-align:left") (style 'table "border-spacing: 10px;border:28px ridge orange") ;; special biblical border (style 'th "color:blue;") </lang>
- Output:
<lang scheme>
- changed <angry> to to show that html tags inside text are correctly transmitted.
(define MontyPython #<<
Character,Speech The multitude,The messiah! Show us the messiah! Brians mother,Now you listen here! He's not the messiah; he's a very naughty boy! Now go away! The multitude,Who are you? Brians mother,I'm his mother; that's who! The multitude,Behold his mother! Behold his mother!
>>#)
(define (task speech) (define table (csv->table speech)) (stack html) (emit-tag 'table h-table table) (html-dump))
(task MontyPython) </lang>
Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | Now you listen here! He's not the messiah; he's a very naughty boy! Now go away! |
The multitude | Who are you? |
Brians mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
Erlang
Using functions from Create_an_HTML_table <lang Erlang> -module( csv_to_html ).
-export( [table_translation/1, task/0] ).
table_translation( CSV ) -> [Headers | Contents] = [string:tokens(X, ",") || X <- string:tokens( CSV, "\n")], Table = create_html_table:html_table( [{border, "1"}, {cellpadding, "10"}], Headers, Contents ), create_html_table:external_format( Table ).
task() -> table_translation( csv() ).
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!". </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! |
Euphoria
<lang euphoria>constant input = "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!"
puts(1,"
\n\n\n")
for i = 1 to length(input) do switch input[i] docase '\n' then puts(1," | |
") case ',' then puts(1," | ")
case '<' then puts(1,"<") case '>' then puts(1,">") case '&' then puts(1,"&") case else puts(1,input[i]) end switch end for puts(1," |
")</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>
F#
Use .NET XmlWriter. Stylesheet styling is applied only when command line option -h ist given. <lang fsharp>open System open System.Text open System.Xml
let 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! """
let csv =
Array.map (fun (line : string) -> line.Split(',')) (data.Trim().Split([|'\n';'\r'|],StringSplitOptions.RemoveEmptyEntries))
[<EntryPoint>]
let main argv =
let style = argv.Length > 0 && argv.[0] = "-h" Console.OutputEncoding <- UTF8Encoding() let xs = XmlWriterSettings() xs.Indent <- true // be friendly to humans use x = XmlWriter.Create(Console.Out, xs) x.WriteStartDocument() x.WriteDocType("HTML", null, null, null) // HTML5 x.WriteStartElement("html") x.WriteStartElement("head") x.WriteElementString("title", "Rosettacode - CSV to HTML translation") if style then x.WriteStartElement("style"); x.WriteAttributeString("type", "text/css") x.WriteString(""" table { border-collapse: collapse; } td, th { border: 1px solid black; padding: .25em} th { background-color: #EEE; } tbody th { font-weight: normal; font-size: 85%; } """) x.WriteEndElement() // style x.WriteEndElement() // head x.WriteStartElement("body") x.WriteStartElement("table") x.WriteStartElement("thead"); x.WriteStartElement("tr") for part in csv.[0] do x.WriteElementString("th", part) x.WriteEndElement(); x.WriteEndElement() // tr thead x.WriteStartElement("tbody") for line in csv.[1..] do x.WriteStartElement("tr") x.WriteElementString("th", line.[0]) x.WriteElementString("td", line.[1]) x.WriteEndElement() // tr x.Close() 0</lang>
- Output:
(stylesheet version)
<lang html5><?xml version="1.0" encoding="utf-8"?> <!DOCTYPE HTML > <html>
<head> <title>Rosettacode - CSV to HTML translation</title> <style type="text/css"> table { border-collapse: collapse; } td, th { border: 1px solid black; padding: .25em} th { background-color: #EEE; } tbody th { font-weight: normal; font-size: 85%; } </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>
Factor
<lang factor>USING: combinators csv io kernel sequences strings ; IN: rosetta-code.csv-to-html
CONSTANT: input
"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!"
- escape-chars ( seq -- seq' )
[ { { CHAR: & [ "&" ] } { CHAR: ' [ "'" ] } { CHAR: < [ "<" ] } { CHAR: > [ ">" ] } [ 1string ] } case ] { } map-as concat ;
- tag ( str tag -- <tag>str</tag> )
[ "<" ">" surround ] [ "</" ">" surround ] bi surround ;
- csv>table ( seq -- str )
[ [ "td" tag ] map concat "tr" tag " " prepend ] map
{ "
" } prepend { "" } append "\n" join ;
input escape-chars string>csv csv>table print</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>
Forth
<lang forth>: BEGIN-COLUMN ." " ;
- END-COLUMN ." " ;
- BEGIN-ROW ." " BEGIN-COLUMN ;
- END-ROW END-COLUMN ." " CR ;
- CSV2HTML
."
" CR BEGIN-ROW BEGIN KEY DUP #EOF <> WHILE CASE 10 OF END-ROW BEGIN-ROW ENDOF [CHAR] , OF END-COLUMN BEGIN-COLUMN ENDOF [CHAR] < OF ." <" ENDOF [CHAR] > OF ." >" ENDOF [CHAR] & OF ." &" ENDOF DUP EMIT ENDCASE REPEAT END-ROW ."" CR
CSV2HTML BYE</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>
Fortran
The plan here is to scan each line for commas to find the splitters between texts, then write the texts out with suitable td and /td swaddling. Text presented as a quoted string (that could thereby contain a comma that is not a delimiter) is explicitly not recognised and apostrophes are apostrophes. Similarly, no attempt is made to recognise characters within the texts that might cause trouble, either because they will not elicit the same glyph when rendered from .html, or because they trigger interpretative action rather than be passed through as-is. Thus the lurking "angry" markings in the texts are not given special conversion. Further, leading and trailing spaces in each text are not trimmed off as the .html rendition process ignores them anyway. To remove them would seem to be easy enough via the special intrinsic function TRIM (available in F90) were it not that it trims off only trailing spaces. Otherwise one could mess with arrays such as IST and LST to finger the first and last character position of each text and deal patiently with the complications attendant on entirely blank or null strings when scanning the input line to determine the values.
The source is only just F90. It uses an array with a specified lower bound (of zero) - with older Fortran you could play with EQUIVALENCE or else diligently remember the offset. More difficult is the arrangement for ascertaining the length of a record as it is being read, with protection against overflowing the scratchpad should it be longer than is allowed for. This requires the Q format code, and was a common extension to F77. As usual, in the absence of help from the filesystem, the length of the longest record could only be determined through reading the entire file, and for this example it is not worth the annoyance. In the absence of the Q format feature, the input record would be read into ALINE with possibly many trailing spaces added to fill out the scratchpad; more time would be lost in scanning backwards to find the last non-blank. Should a record be longer than the scratchpad then its tail end would be lost and no remark made. Some systems (such as Snobol) are able to read a record and prepare a text variable of the correct size for that record, whatever its length (up to some integer limit such as 65535, or even more) but Fortran is not one such.
The key statement is the compound WRITE statement and its associated FORMAT, and for non-furrytranners these proceedings may be obscure. A WRITE statement accepts a list of items to be written in the usual manner, and an item is usually the name of a variable or an expression (such as 2*X + 1), but it can also be an implied DO-list. In this case the item is enclosed in brackets, and within them starts with an item list followed by a comma and a DO-expression, as in (a,b,c, I = 1,N)
where a, b and c constitute a three-element list of items - any of which could themselves be an implied DO-list if nested lists were desired. Thus, by one means or another, the WRITE statement produces a sequence of values (of various types) to be sent forth. In association with the list of entries in the nominated FORMAT statement: processing proceeds in parallel through both lists in the manner of coroutines, not sequentially. It is possible with a READ statement that a value just read adjusts a part of a FORMAT statement not yet encountered during the processing of the READ statement. For instance FORMAT 13 could have <NCOLS> instead of 666 as its repeat count, but this is an extension to F77 and avoided here to stick with older abilities except where inconvenient.
Thus, the entire line for a table row can be written in one go, starting with the tr then many repetitions of (WOT,text, WOT), with each starting and ending WOT appropriately encased by < and > and / characters supplied by the FORMAT. This repeated pattern is unsuitable for starting the line (so the tr is provided by the FORMAT, with indentation) because then it would be out of step, but happily, after the last text is rolled, the required /tr can be sent to use the format codes that would normally be used for the start of the next text. Humm. If there were to be 666 texts to roll, this will exhaust the FORMAT statement and it will write the current line out and start a fresh one, resuming at the rightmost ( in the FORMAT specification. This rule does not always prove convenient so I'd prefer the vertical bar usage of musical notation to mark the resumption location. Interpreters of html do not care about layout but humans do, so, just in case, the repeat count should be 667 (or <NCOLS + 1>), or, if <NCOLS> were used, there could follow a ,A
in the FORMAT, or, the "/tr" could be removed from the WRITE and appended to end the FORMAT just as at its start, but enough.
The check for a comma is not ALINE(I:I).EQ.","
because in other work this usage has been found to evoke astoundingly bad code, notably that both appearances of "I" are checked as being within bounds, and, the length is calculated by subtracting the "first" (I) from the "last" (also I) at run time! At least by the COMPAQ F90/95 compiler. By contrast, the ICHAR usage, which can only be for a single character, lacks this madness and far superior speed results. Not important in this example, but it explains why this puzzling usage appeared in a prog. at the Culham Science Centre in source from an IBM mainframe.
<lang Fortran>
SUBROUTINE CSVTEXT2HTML(FNAME,HEADED) !Does not recognise quoted strings.
Converts without checking field counts, or noting special characters.
CHARACTER*(*) FNAME !Names the input file. LOGICAL HEADED !Perhaps its first line is to be a heading. INTEGER MANY !How long is a piece of string? PARAMETER (MANY=666) !This should suffice. CHARACTER*(MANY) ALINE !A scratchpad for the input. INTEGER MARK(0:MANY + 1) !Fingers the commas on a line. INTEGER I,L,N !Assistants. CHARACTER*2 WOT(2) !I don't see why a "table datum" could not be for either. PARAMETER (WOT = (/"th","td"/)) !A table heding or a table datum INTEGER IT !But, one must select appropriately. INTEGER KBD,MSG,IN !A selection. COMMON /IOUNITS/ KBD,MSG,IN !The caller thus avoids collisions. OPEN(IN,FILE=FNAME,STATUS="OLD",ACTION="READ",ERR=661) !Go for the file. WRITE (MSG,1) !Start the blather.
1 FORMAT ("
") !By stating that a table follows. MARK(0) = 0 !Syncopation for the comma fingers. N = 0 !No records read. 10 READ (IN,11,END = 20) L,ALINE(1:MIN(L,MANY)) !Carefully acquire some text. 11 FORMAT (Q,A) !Q = number of characters yet to read, A = characters. N = N + 1 !So, a record has been read. IF (L.GT.MANY) THEN !Perhaps it is rather long? WRITE (MSG,12) N,L,MANY !Alas! 12 FORMAT ("Line ",I0," has length ",I0,"! My limit is ",I0) !Squawk/ L = MANY !The limit actually read. END IF !So much for paranoia. IF (N.EQ.1 .AND. HEADED) THEN !Is the first line to be treated specially? WRITE (MSG,*) "<tHead>" !Yep. Nominate a heading. IT = 1 !And select "th" rather than "td". ELSE !But mostly, IT = 2 !Just another row for the table. END IF !So much for the first line. NCOLS = 0 !No commas have been seen. DO I = 1,L !So scan the text for them. IF (ICHAR(ALINE(I:I)).EQ.ICHAR(",")) THEN !Here? NCOLS = NCOLS + 1 !Yes! MARK(NCOLS) = I !The texts are between commas. END IF !So much for that character. END DO !On to the next. NCOLS = NCOLS + 1 !This is why the + 1 for the size of MARK. MARK(NCOLS) = L + 1 !End-of-line is as if a comma was one further along. WRITE (MSG,13) !Now roll all the texts. 1 (WOT(IT), !This starting a cell, 2 ALINE(MARK(I - 1) + 1:MARK(I) - 1), !This being the text between the commas, 3 WOT(IT), !And this ending each cell. 4 I = 1,NCOLS), !For this number of columns. 5 "/tr" !And this ends the row. 13 FORMAT (" ",666("<",A,">",A,"</",A,">")) !How long is a piece of string? IF (N.EQ.1 .AND. HEADED) WRITE (MSG,*) "</tHead>" !Finish the possible header. GO TO 10 !And try for another record. 20 CLOSE (IN) !Finished with input. WRITE (MSG,21) !And finished with output. 21 FORMAT ("") !This writes starting at column one.
RETURN !Done!
Confusions.
661 WRITE (MSG,*) "Can't open file ",FNAME !Alas. END !So much for the conversion.
INTEGER KBD,MSG,IN COMMON /IOUNITS/ KBD,MSG,IN KBD = 5 !Standard input. MSG = 6 !Standard output. IN = 10 !Some unspecial number.
CALL CSVTEXT2HTML("Text.csv",.FALSE.) !The first line is not special. WRITE (MSG,*) CALL CSVTEXT2HTML("Text.csv",.TRUE.) !The first line is a heading. END
</lang>
- Output:
<Table border=1> <tr><td>Character</td><td>Speech</td></tr> <tr><td>The multitude</td><td>The messiah! Show us the messiah!</td></tr> <tr><td>Brian's 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>Brian's 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> <Table border=1> <tHead> <tr><th>Character</th><th>Speech</th></tr> </tHead> <tr><td>The multitude</td><td>The messiah! Show us the messiah!</td></tr> <tr><td>Brian's 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>Brian's 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>
And interpreted, first with no special heading:
Character | Speech |
The multitude | The messiah! Show us the messiah! |
Brian's 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? |
Brian's mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
</tHead>
Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brian's 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? |
Brian's mother | I'm his mother; that's who! |
The multitude | Behold his mother! Behold his mother! |
Go
<lang go>package main
import (
"bytes" "encoding/csv" "fmt" "html/template" "strings"
)
var c = `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() {
if h, err := csvToHtml(c); err != nil { fmt.Println(err) } else { fmt.Print(h) }
}
func csvToHtml(c string) (string, error) {
data, err := csv.NewReader(bytes.NewBufferString(c)).ReadAll() if err != nil { return "", err } var b strings.Builder
err = template.Must(template.New("").Parse(`
{{.}} |
`)).Execute(&b, data)
return b.String(), err
}</lang> Extra credit version accepts -h command line option to do the special formatting for the heading line. <lang go>package main
import (
"bytes" "encoding/csv" "flag" "fmt" "html/template" "strings"
)
var csvStr = `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(csvStr, *headings); err != nil { fmt.Println(err) } else { fmt.Print(html) }
}
func csvToHtml(csvStr string, headings bool) (string, error) {
data, err := csv.NewReader(bytes.NewBufferString(csvStr)).ReadAll() if err != nil { return "", err } tStr := tPlain if headings { tStr = tHeadings } var b strings.Builder err = template.Must(template.New("").Parse(tStr)).Execute(&b, data) return b.String(), err
}
const (
tPlain = `
{{.}} |
`
tHeadings = `
<thead></thead> <tbody>Template:EndTemplate:End </tbody>Template:End
{{.}} |
{{.}} |
---|
` )</lang>
- Output:
Extra credit version with -h
<lang html>
<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>
Basic version, or extra credit version without -h
<lang 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! |
</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>--import Data.List.Split (splitOn) -- if the import is available splitOn :: Char -> String -> [String] -- otherwise splitOn delim = foldr (\x rest ->
if x == delim then "" : rest else (x:head rest):tail rest) [""]
htmlEscape :: String -> String htmlEscape = concatMap escapeChar
where escapeChar '<' = "<" escapeChar '>' = ">" escapeChar '&' = "&" escapeChar '"' = """ --" escapeChar c = [c]
toHtmlRow :: [String] -> String
toHtmlRow [] = "" toHtmlRow cols = let htmlColumns = concatMap 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 = interact csvToTable</lang>
Compact version <lang haskell>import Data.List (unfoldr) split p = unfoldr (\s -> case dropWhile p s of [] -> Nothing
ss -> Just $ break p ss)
main = interact (\csv -> "
\n" ++ (unlines $ map ((\cols -> "\n" ++ (concatMap (\x -> " \n") cols) ++ "") . split (==',')) $ lines csv) ++ "" ++ concatMap (\c ->
case c of {'<' -> "<"; '>' -> ">"; '&' -> "&"; '"' -> """; _ -> [c]}) x ++ " |
")</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
for extended solution: java -cp . Csv2Html header < text.csv
<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.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"); stdout.println("<html xmlns=\"http://www.w3.org/1999/xhtml\">"); stdout.println("<head><meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\"/>"); stdout.println("<title>Csv2Html</title>"); stdout.println("<style type=\"text/css\">"); stdout.println("body{background-color:#FFF;color:#000;font-family:OpenSans,sans-serif;font-size:10px;}"); stdout.println("table{border:0.2em solid #2F6FAB;border-collapse:collapse;}"); stdout.println("th{border:0.15em solid #2F6FAB;padding:0.5em;background-color:#E9E9E9;}"); stdout.println("td{border:0.1em solid #2F6FAB;padding:0.5em;background-color:#F9F9F9;}</style>"); stdout.println("</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>
- simple solution:
<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><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
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>
- extended:
<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><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
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>
JavaScript
<lang JavaScript>var csv = "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!";
var lines = csv.replace(/&/g, '&')
.replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .split(/[\n\r]/) .map(function(line) { return line.split(',')})
.map(function(row) {return '\t\t' + row[0] + '' + row[1] + '';}); console.log('
\n\t<thead>\n' + lines[0] + '\n\t</thead>\n\t<tbody>\n' + lines.slice(1).join('\n') + '\t</tbody>\n');
</lang>
<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>
- 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>
jq
We will assume the input is in a file named csv2html.csv, and that the jq program as given below is in a file named csv2html.jqn. To simplify things, we will invoke the jq processor twice -- the first invocation simply converts the text input into a sequence of JSON strings: <lang jq>jq -R . csv2html.csv | jq -r -s -f csv2html.jq </lang><lang jq>def headerrow2html:
[" <thead> "] + (split(",") | map(" \(@html)")) + [ " </thead>" ]
def row2html: [" "] + (split(",") | map(" \(@html)")) + [ " " ]
def csv2html: def rows: reduce .[] as $row ([]; . + ($row | row2html)); ["
"] + (.[0] | headerrow2html) + (.[1:] | rows) + [ ""]
csv2html | .[]</lang>
Output
<lang html5>
<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>
Jsish
From Javascript entry.
<lang javascript>/* CSV to HTML, in Jsish */ var csv = "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!";
var lines = csv.replace(/&/g, '&')
.replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .split('\n') .map(function(line) { return line.split(','); })
.map(function(row) { return '\t\t' + row[0] + '' + row[1] + ''; });
if (Interp.conf('unitTest')) {
puts('
\n\t<thead>\n' + lines[0] + '\n\t</thead>\n\t<tbody>\n' + lines.slice(1).join('\n') + '\t</tbody>\n');
}
/*
!EXPECTSTART!
<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! |
!EXPECTEND!
- /</lang>
- Output:
prompt$ jsish -u csvToHTML.jsi [PASS] csvToHTML.jsi
Julia
<lang Julia>using DataFrames, CSV
using CSV, DataFrames
function csv2html(fname; header::Bool=false)
csv = CSV.read(fname) @assert(size(csv, 2) > 0) str = """
<html>
<head>
<style type="text/css"> body { margin: 2em; } h1 { text-align: center; } table { border-spacing: 0; box-shadow: 0 0 0.25em #888; margin: auto; } table, tr, th, td { border-collapse: collapse; } th { color: white; background-color: rgb(43, 53, 59); } th, td { padding: 0.5em; } table tr:nth-child(even) td { background-color: rgba(218, 224, 229, 0.850); } </style>
</head>
<body>
csv2html Example
""" tags = header ? ("") : ("")for i=1:size(csv, 2) str *= " " * tags[1] * csv[1, i] * tags[2] * "\n" endstr *= " "^8 * "\n" for i=2:size(csv, 1) str *= " \n" for j=1:size(csv, 2) str *= " " * "\n"
endstr *= " \n" end str * "
", " | ", " |
---|---|
" * csv[i, j] * " |
\n</body>\n\n</html>\n"
end
print(csv2html("input.csv", header=true))
</lang>
- Output:
<lang html5><html>
<head>
<style type="text/css"> body { margin: 2em; } h1 { text-align: center; } table { border-spacing: 0; box-shadow: 0 0 0.25em #888; margin: auto; } table, tr, th, td { border-collapse: collapse; } th { color: white; background-color: rgb(43, 53, 59); } th, td { padding: 0.5em; } table tr:nth-child(even) td { background-color: rgba(218, 224, 229, 0.850); } </style>
</head>
<body>
csv2html Example
Character | Speech |
---|---|
The multitude | The messiah! Show us the messiah! |
Brians mother | Now you listen here! He's not the messiah; he's a very naughty boy! Now go away! |
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>
Kotlin
<lang scala>// version 1.1.3
val csv =
"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!"
fun main(args: Array<String>) {
val i = " " // indent
val sb = StringBuilder("
\n$i\n$i$i\n$i\n$i\n$i$i\n$i$i\n$i\n")
for (c in csv) { sb.append( when (c) {'\n' -> " | |
" ',' -> " | "
'&' -> "&" '\ -> "'" '<' -> "<" '>' -> ">" else -> c.toString() }) }sb.append(" |
")
println(sb.toString()) println()
// now using first row as a table header sb.setLength(0)
sb.append("
\n$i<thead>\n$i$i\n$i$i$i\n$i$i\n$i</thead>\n$i<tbody>\n$i$i\n$i$i$i\n$i$i$i\n$i$i\n$i$i\n$i$i$i\n$i$i$i\n$i$i\n$i</tbody>\n")
val hLength = csv.indexOf('\n') + 1 // find length of first row including CR for (c in csv.take(hLength)) { sb.append( when (c) {'\n' -> " | |
" ',' -> " | "
else -> c.toString() }) } for (c in csv.drop(hLength)) { sb.append( when (c) {'\n' -> " |
" ',' -> " | "
'&' -> "&" '\ -> "'" '<' -> "<" '>' -> ">" else -> c.toString() }) }sb.append(" |
")
println(sb.toString())
}</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! |
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>
Liberty BASIC
<lang lb>
newline$ ="|" ' No escape behaviour, so can't refer to '/n'. ' Generally imported csv would have separator CR LF; easily converted first if needed
csv$ ="Character,Speech" +newline$+_ "The multitude,The messiah! Show us the messiah!" +newline$+_ "Brians mother,<angry>Now you listen here! He's not the messiah; he's a very naughty boy! Now go away!</angry>" +newline$+_ "The multitude,Who are you?" +newline$+_ "Brians mother,I'm his mother; that's who!" +newline$+_ "The multitude,Behold his mother! Behold his mother!"
print "<HTML>" print "<HEAD>" print "</HEAD>" print "<BODY>"
print "
CSV to HTML translation
" print "
" print "": print "" print ""
for i =1 to len( csv$) c$ =mid$( csv$, i, 1) select case c$case "|": print " | |
" case ",": print " | ";
case "<": print "&"+"lt;"; case ">": print "&"+"gt;"; case "&": print "&"+"amp;"; case else: print c$; end select next iprint " |
"
print "</BODY>" print "</HTML>" end
</lang>
- Output:
<HTML> <HEAD> </HEAD> <BODY> <center><H1>CSV to HTML translation </H1></center> <table border=1 cellpadding =10> <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> </BODY> </HTML>
Rendered output is available at http://www.diga.me.uk/csvhtml.gif
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>
Maple
<lang maple> #A translation of the C code posted html_table := proc(str) local char;
printf("
\n\n\n");
for char in str do if char = "\n" thenprintf(" | |
")
elif char = "," thenprintf(" | ")
elif char = "<" then printf("<") elif char = ">" then printf(">") elif char = "&" then printf("&") else printf(char) end if; end do;printf(" |
");
end proc;
html_table("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>
- 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>
Mathematica / Wolfram Language
<lang Mathematica>a="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!"; (*Naive*)
StringJoin["
\n",Map[StringJoin["\n"]&, StringSplit[StringReplace[a,{","->"",#," |
","<"->"<",">"->">"}],"\n"]] ," |
"]
(*Extra*)
StringJoin["
\n",StringJoin["\n"]&[ StringSplit[StringReplace[a,{","->"\n"]&, StringSplit[StringReplace[a,{","->"",#," |
---|
","<"->"<",">"->">"}],"\n"]//First] ,Map[StringJoin[" |
",#," |
","<"->"<",">"->">"}],"\n"]//Rest] ," |
"]
</lang>
- Naive:
<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>
- Extra:
<table> <tr><th>Character</td><td>Speech</th></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>
MATLAB
Many specialized MATLAB file IO functions are painfully slow, and with large files it is often better to use a lower-level functions such as fread. Here we use fileread, which does a little bit of error handling and calls fread, specifying the input data as text. From this text string, we can easily convert any special html characters, split it into a cell array, and print it out specifying format.
<lang MATLAB> inputString = fileread(csvFileName);
% using multiple regular expressions to clear up special chars
htmlFriendly = regexprep(regexprep(regexprep(regexprep(inputString,...
'&','&'),... '"','"'),... '<','<'),... '>','>'); % split string into cell array
tableValues = regexp(regexp(htmlFriendly,'(\r\n|\r|\n)','split')',',','split');
%%% print in html format %%% % <Extra Credit> first line gets treated as header
fprintf(1,['
\n\t' sprintf('\n\t\t',tableValues{1,:}{:})])% print remaining lines of csv as html table (rows 2:end in cell array of csv values)cellfun(@(x)fprintf(1,['\n\t' sprintf('\n\t\t',x{:}) '\n\t']),tableValues(2:end)) fprintf(1,'\n
%s |
---|
%s |
')
</lang> As a single line: <lang MATLAB>
fprintf(1,['
\n\t\n\t\t\n\t\t\n\t\n\t\t\n','\n','once'),',','\n\t\t\n\t\n',regexprep(regexprep(regexprep(regexprep(regexprep(regexprep(regexprep(regexprep(fileread(cvsFileName),'&','&'),'"','"'),'<','<'),'>','>'),'(?<=(^[^\n\r]*)),',' | '),'(?<!>)(\r\n|\r|\n)','\n\t |
---|---|
'),' | '),' |
\n'])
</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>
Maxima
<lang Maxima>infile: "input.csv"; outfile: "table.html"; instream: openr(infile); outstream: openw(outfile);
printf(outstream, "
~%"); nr: 0; while (line: readline(instream))#false do ( nr: nr + 1, line: ssubst("<", "<", line), line: ssubst(">", ">", line), value_list: map(lambda([f], strim(" ", f)), split(line, ",")), if nr=1 then printf(outstream, " <THEAD bgcolor=\"yellow\">") else printf(outstream, " <TBODY bgcolor=\"orange\">"), printf(outstream, ""), for value in value_list do printf(outstream, "", value), printf(outstream, ""), if nr=1 then printf(outstream, "</THEAD>~%") else printf(outstream, "</TBODY>~%")); printf(outstream, "~a |
~%");
close(instream); close(outstream);</lang>
<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>
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>
Nanoquery
<lang nanoquery>// a method that converts a csv row into a html table row as a string def toHtmlRow(record, tag)
htmlrow = "\t\n" // loop through the values in the current csv row for i in range(1, len(record)) htmlrow = htmlrow + "\t\t<" + tag + ">" + (record ~ i) + "</" + tag + ">\n" end for return htmlrow + "\t\n" end def // get the name of the csv file then open it print "filename: " input fname open fname // allocate a string to hold the table htmltable = "
\n" // add the column names to the table (#0 returns column names as a record object) htmltable = (htmltable + toHtmlRow(#0, "th")) // add all other rows to the table for i in range(1, $dbsize) htmltable = (htmltable + toHtmlRow(#i, "td")) end for // close the html table htmltable = htmltable+""
println htmltable</lang>
NetRexx
Uses the NetRexx solution for Read a file line by line to read the CSV file into the program. <lang NetRexx>/* NetRexx */ options replace format comments java crossref symbols nobinary
parse arg inFileName . if inFileName = | inFileName = '.' then inFileName = './data/Brian.csv' csv = RREadFileLineByLine01.scanFile(inFileName)
header = htmlHeader() pre = htmlCsvText(csv, inFileName) table = htmlCsvTable(csv, inFileName) footer = htmlFooter()
say header say pre say table say footer
return
method htmlHeader() public static returns Rexx
html = '<?xml version="1.0" encoding="UTF-8"?>\n' - || '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n' - || '<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">\n' - || '<head>\n' - || '<meta http-equiv="Content-type" content="text/html;charset=UTF-8"/>\n' - || '<title>RCsv2Html</title>\n' - || '<style type="text/css">\n' - || '\n' - || '</style>\n' - || '</head>\n' - || '<body>\n' -
|| '
Rosetta Code – NetRexx Sample Output
\n' - || '
<a href="http://rosettacode.org/wiki/CSV_to_HTML_translation">CSV to HTML translation</a>
\n' -
||
return html
method htmlFooter() public static returns Rexx
html = '</body>\n' - || '</html>\n' - || return html
method htmlCsvText(csv, fileName = '.') public static returns Rexx
html = '
Contents of CSV 'fileName'
\n' - || '
\n' - || '' loop row = 1 to csv[0] html = html || csv[row]'\n' end row html = html - || '
\n' -
|| return html
method htmlCsvTable(csv, fileName = '.') public static returns Rexx
html = '
\n' - || '\n' - || '<thead>\n' - || html = html - || htmlCsvTableRow(csv[1], 'th')'\n' - || '</thead>\n' - || '<tbody>\n' - || loop r_ = 2 to csv[0] html = html - || htmlCsvTableRow(csv[r_])'\n' - || end r_ html = html - || '</tbody>\n' - || '\n' -
|| return html
method htmlCsvTableRow(row, tag = 'td') public static returns Rexx
row = row.strip('t') row = row.changestr('&', '&') -- need to do this one first to avoid double translation row = row.changestr('"', '"') row = row.changestr("'", ''') row = row.changestr('<', '<') row = row.changestr('>', '>') elmts = elmts[0] = 0 e_ = 0 loop while row.length() > 0 parse row elmt ',' row e_ = e_ + 1; elmts[0] = e_; elmts[e_] = elmt end
html = '\n' - || loop e_ = 1 to elmts[0] html = html - || '<'tag'>'elmts[e_]'</'tag'>\n' - || end e_ html = html - || '\n' - || return html </lang> Output:
<lang html5><?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US"> <head> <meta http-equiv="Content-type" content="text/html;charset=UTF-8"/> <title>RCsv2Html</title> <style type="text/css"> </style> </head> <body>
Rosetta Code – NetRexx Sample Output
<a href="http://rosettacode.org/wiki/CSV_to_HTML_translation">CSV to HTML translation</a>
Contents of CSV ./data/Brian.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!<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>
Rendered Output:
Nim
<lang nim>import cgi, strutils
const csvtext = """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!"""
proc row2tr(row): string =
result = "" let cols = xmlEncode(row).split(",") for col in cols: result.add ""&col&"" result.add "" proc csv2html(txt): string = result = "
\n" for row in txt.splitLines(): result.add " <tbody>"&row2tr(row)&"</tbody>\n" result.add ""
echo csv2html(csvtext)</lang>
- Output:
<table summary="csv2html program output"> <tbody><tr><td>Character</td><td>Speech</td></tr></tbody> <tbody><tr><td>The multitude</td><td>The messiah! Show us the messiah!</td></tr></tbody> <tbody><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></tbody> <tbody><tr><td>The multitude</td><td>Who are you?</td></tr></tbody> <tbody><tr><td>Brians mother</td><td>I'm his mother; that's who!</td></tr></tbody> <tbody><tr><td>The multitude</td><td>Behold his mother! Behold his mother!</td></tr></tbody> </table>
Oberon-2
<lang oberon2> MODULE CSV2HTML; IMPORT
Object, IO, IO:FileChannel, IO:TextRider, SB := ADT:StringBuffer, NPCT:Tools, NPCT:CGI:Utils, Ex := Exception, Out;
VAR
fileChannel: FileChannel.Channel; rd: TextRider.Reader; line: ARRAY 1024 OF CHAR; table: SB.StringBuffer; parts: ARRAY 2 OF STRING; PROCEDURE DoTableHeader(sb: SB.StringBuffer;parts: ARRAY OF STRING); BEGIN
sb.Append(""+Utils.EscapeHTML(parts[0])+""+Utils.EscapeHTML(parts[1])+"");
sb.AppendLn END DoTableHeader; PROCEDURE DoTableRow(sb: SB.StringBuffer;parts: ARRAY OF STRING); BEGIN
sb.Append(""+Utils.EscapeHTML(parts[0])+""+Utils.EscapeHTML(parts[1])+"");
sb.AppendLn END DoTableRow; PROCEDURE DoTable(sb: SB.StringBuffer): STRING; VAR aux: SB.StringBuffer; BEGIN
aux := SB.New("
");aux.AppendLn; RETURN aux.ToString() + sb.ToString() + "";
END DoTable;
BEGIN
TRY fileChannel := FileChannel.OpenUnbuffered("script.csv",{FileChannel.read}); CATCH Ex.Exception(ex): Out.Object(ex.GetMessage());Out.Ln; HALT(1) END; rd := TextRider.ConnectReader(fileChannel); (* Extract headers *) TRY rd.ReadLine(line); table := NEW(SB.StringBuffer,2048); Tools.Split(Object.NewLatin1(line),",",parts); DoTableHeader(table,parts); CATCH IO.Error(ex): Out.Object(ex.Name() + ": " + ex.GetMessage());Out.Ln; HALT(2) END; (* Extract data *) LOOP TRY rd.ReadLine(line); IF (line[0] # 0X)THEN (* skip empty lines *) Tools.Split(Object.NewLatin1(line),",",parts); DoTableRow(table,parts) END CATCH IO.Error(ex): EXIT END END; Out.Object(DoTable(table));Out.Ln; fileChannel.Close()
END CSV2HTML. </lang>
- Output:
<table> <tr><th>Character</th><th>Speech</th></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>
Objeck
<lang objeck>use System.IO.File; use Data.CSV;
class CsvToHtml {
function : Main(args : String[]) ~ Nil { if(args->Size() = 1) { table := CsvTable->New(FileReader->ReadFile(args[0])); if(table->IsParsed()) {
buffer := "<html><body>
"; Header(table->GetHeaders(), buffer); for(i := 1; i < table->Size(); i += 1;) { Data(table->Get(i), buffer); }; buffer += "</body></html>";
buffer->PrintLine(); }; }; }
function : Header(row : CsvRow, buffer : String) ~ Nil {
buffer += ""; each(i : row) { buffer += "";
buffer += Encode(row->Get(i));
buffer += ""; }; buffer += ""; } function : Data(row : CsvRow, buffer : String) ~ Nil { buffer += ""; each(i : row) { buffer += "";
buffer += Encode(row->Get(i));
buffer += ""; }; buffer += ""; } function : Encode(in : String) ~ String { out := ""; each(i : in) { c := in->Get(i); select(c) { label '&': { out->Append("&"); } label '\: { out->Append("'"); } label '<': { out->Append("<"); } label '>': { out->Append(">"); } other: { out->Append(c); } }; }; return out; } } </lang> Output:
<html><body><table><tr><th>Character</th><th>Speech</th></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></body></html>
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>
- 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>
Perl 6
A very lispy solution: <lang perl6>my $str = "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!";
- comment the next line out, if you want to read from standard input instead of the hard-coded $str above
- my $str = $*IN.slurp;
my &escape = *.trans(« & < > » => « & < > »); # a function with one argument that escapes the entities my &tag = {"<$^tag>"~$^what~"</$^tag>"};
printf '<!DOCTYPE html> <html> <head><title>Some Text</title></head>
<body>
%s</body></html>
', [~] # concatenation reduction ('a', 'b', 'c') → 'abc' (escape($str).split(/\n/) # escape the string and split at newline
==> map -> $line {tag 'tr', # feed that into a map, that map function will tag as 'tr, and has an argument called $line ([~] $line.split(/','/)\ # split $line at ',', # that / at the end is just an unspace, you can omit it, but then you have to delete # all whitespace and comments between split(…) and .map .map({tag 'td', $^cell}))})\ # map those cells as td
.join("\n"); # append a newline for nicer output</lang>
- Output:
<lang html><!DOCTYPE html> <html> <head><title>Some Text</title></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>
Phix
Copy of Euphoria <lang Phix>constant input = "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!"
puts(1,"
\n\n\n")
for i = 1 to length(input) do switch input[i] docase '\n' then puts(1," | |
") case ',' then puts(1," | ")
case '<' then puts(1,"<") case '>' then puts(1,">") case '&' then puts(1,"&") case else puts(1,input[i]) end switch end for puts(1," |
")</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>
PHP
Simple Solution
<Lang php> <?php $csv = <<<EOT 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! EOT;
function convert($csv) {
$out = []; array_map(function($ln) use(&$out) { $ln = htmlentities($ln); $out[] = count($out) == 0
? '<thead>'.implode('',explode(',',$ln))."</thead>\n" : ''.implode('',explode(',',$ln))."\n";
}, explode("\n",$csv));
return '
'.implode(,$out).'';
}
echo convert($csv); </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:
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:
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.
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 all three 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>
Robust solution
This solution uses the CSV parser and HTML-capable XML serializer included in the Python standard library to produce the same fancy table as in the "extra credit" version.
While not strictly necessary for the very constrained input given in Rosetta Code, using readily available high-level APIs is idiomatic for Python, makes bugs easier to catch, and this also demonstrates the kind of "safe to use with more general inputs" code that is good to get in the habit of reaching for when dealing with real-world inputs and outputs.
(eg. Suppose an earlier stage in the pipeline is using a proper CSV-generating library but is running in a locale that uses commas for decimal separators and has a bug that causes it to unexpectedly start feeding pretty-printed floating-point in. Using a proper CSV reader minimizes the potential harm and helps the program to raise errors in the most elucidating place.)
Since the version of ElementTree in the standard library does not support pretty-printing, the output it produces is minified. Unlike the "extra credit" version, this doesn't put each <TR>
element in its own <TBODY>
.
<lang python>from csv import DictReader from xml.etree import ElementTree as ET
def csv2html_robust(txt, header=True, attr=None):
# Use DictReader because, despite what the docs say, reader() doesn't # return an object with .fieldnames # (DictReader expects an iterable that returns lines, so split on \n) reader = DictReader(txt.split('\n'))
table = ET.Element("TABLE", **attr.get('TABLE', {})) thead_tr = ET.SubElement( ET.SubElement(table, "THEAD", **attr.get('THEAD', {})), "TR") tbody = ET.SubElement(table, "TBODY", **attr.get('TBODY', {}))
if header: for name in reader.fieldnames: ET.SubElement(thead_tr, "TD").text = name
for row in reader: tr_elem = ET.SubElement(tbody, "TR", **attr.get('TR', {}))
# Use reader.fieldnames to query `row` in the correct order. # (`row` isn't an OrderedDict prior to Python 3.6) for field in reader.fieldnames: td_elem = ET.SubElement(tr_elem, "TD", **attr.get('TD', {})) td_elem.text = row[field]
return ET.tostring(table, method='html')
htmltxt = csv2html_robust(csvtxt, True, {
'TABLE': {'border': "1", 'summary': "csv2html extra program output"}, 'THEAD': {'bgcolor': "yellow"}, 'TBODY': {'bgcolor': "orange"}
})
print(htmltxt.decode('utf8'))</lang>
Sample HTML output
<lang html5>
<THEAD bgcolor="yellow"></THEAD><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
R
Using base R functions only, this is a very basic implementation and produces a simple HTML table <lang rsplus>File <- "~/test.csv" Opened <- readLines(con = File) Size <- length(Opened)
HTML <- "~/test.html"
Table <- list()
for(i in 1:Size) {
#i=1 Split <- unlist(strsplit(Opened[i],split = ","))
Table[i] <- paste0("",Split,"",collapse = "") Table[i] <- paste0("",Table[i],"") } Table[1] <- paste0("
",Table[1]) Table[length(Table)] <- paste0(Table[length(Table)],"")
writeLines(as.character(Table), HTML)</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>
Racket
Uses X-exprs: <lang racket>#lang racket
(define e.g.-CSV
(string-join '("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!") "\n"))
(define (CSV-lines->HTML-table csv)
(define csv-rows (regexp-split "\n" csv)) (define csv-row-cells (map (lambda (row) (regexp-split "," row)) csv-rows)) (define (cell-data->HTML-data data) `(td () ,data)) (define (row-data->HTML-row CSV-row) `(tr () ,@(map cell-data->HTML-data CSV-row) "\n")) `(table (thead ,(row-data->HTML-row (car csv-row-cells))) (tbody ,@(map row-data->HTML-row (cdr csv-row-cells)))))
(require xml) (display (xexpr->string (CSV-lines->HTML-table e.g.-CSV)))</lang>
Sample HTML 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>
Red
<lang Red>Red []
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!}
add2html: func [ bl ] [append html rejoin bl ] ;; helper function to add block data to html string
- ----------------------------------------------------------------------
csv2html: func ["function to generate string with html table from csv data file"
- ----------------------------------------------------------------------
s [string!] "input .csv data"
][ arr: split s newline ;; generate array (series) from string
html: copy "
^/" ;; init html string forall arr [ ;; i use forall here so that i can test for head? of series ... either head? arr [ append html ""] [ append html ""] replace/all first arr "<" "<" ;; escape "<" and ">" characters replace/all first arr ">" ">" foreach col split first arr "," [ either head? arr [ add2html [']][add2html [']
] ]add2html [' newline] ] return add2html ['
col ' | col ' |
---|
]
]
- ----------------------------------------------------------------------
print csv2html csv ;; call function write %data.html csv2html csv ;; write to file </lang> output
<table border=1> <tr bgcolor=wheat><th>Character</th><th>Speech</th></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>
Sample HTML 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! |
Retro
<lang Retro>remapping off "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!" remapping on keepString constant CSV
- display ( c- )
[ ', = ] [ drop "" puts ] when [ 10 = ] [ drop "\n" puts ] when
[ '< = ] [ drop "<" puts ] when [ '> = ] [ drop ">" puts ] when [ '& = ] [ drop "&" puts ] when putc ;
- displayHTML ( $- )
"
\n\n" puts
[ @ display ] ^types'STRING each@" |
" puts ;
CSV displayHTML</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>
REXX
The rendered output was verified using Firefox Aurora with:
- file:///c:/output.html
- file:///c:/outputh.html
<lang rexx>/*REXX program converts CSV ───► HTML table representing the CSV data. */ arg header_ . /*obtain an uppercase version of args. */ wantsHdr= (header_=='HEADER') /*is the arg (low/upp/mix case)=HEADER?*/
/* [↑] determine if user wants a hdr. */ iFID= 'CSV_HTML.TXT' /*the input fileID to be used. */
if wantsHdr then oFID= 'OUTPUTH.HTML' /*the output fileID with header.*/
else oFID= 'OUTPUT.HTML' /* " " " without " */
do rows=0 while lines(iFID)\==0 /*read the rows from a (text/txt) file.*/ row.rows= strip( linein(iFID) ) end /*rows*/
convFrom= '& < > "' /*special characters to be converted. */ convTo = '& < > "' /*display what they are converted into.*/
call write , '<html>'
call write , '
' do j=0 for rows; call write 5, '' tx= 'td' if wantsHdr & j==0 then tx= 'th' /*if user wants a header, then oblige. */ do while row.j\== do k=1 for words(convFrom) yyy=changestr( word( convFrom, k), yyy, word( convTo, k)) end /*k*/ call write 10, '<'tx">"yyy'</'tx">" end /*forever*/ end /*j*/ call write 5, '' call write , '; parse var row.j yyy "," row.j'
call write , '</html>'
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
write: call lineout oFID, left(, 0 || arg(1) )arg(2); return</lang>
Some older REXXes don't have a changestr BIF, so one is included here ──► CHANGESTR.REX.
output
<html> <table border=4 cellpadding=9 cellspacing=1> <tr> <td>Character</td> <td>Speech</td> <tr> <td>The multitude</td> <td>The messiah! Show us the messiah!</td> <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> <td>The multitude</td> <td>Who are you?</td> <tr> <td>Brians mother</td> <td>I'm his mother; that's who!</td> <tr> <td>The multitude</td> <td>Behold his mother! Behold his mother!</td> <tr> </table> </html>
rendered 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! |
output (extra credit solution) when the first argument is HEADER in upper/lower/mixed case (with/without leading/trailing blanks).
<html> <table border=4 cellpadding=9 cellspacing=1> <tr> <th>Character</th> <th>Speech</th> <tr> <td>The multitude</td> <td>The messiah! Show us the messiah!</td> <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> <td>The multitude</td> <td>Who are you?</td> <tr> <td>Brians mother</td> <td>I'm his mother; that's who!</td> <tr> <td>The multitude</td> <td>Behold his mother! Behold his mother!</td> <tr> </table> </html>
rendered 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! |
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>
- 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>
Run BASIC
The extra credit version has 2 extra lines of code to get the heading. <lang rnbasic>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!"
k = instr(csv$,",") ' 2 exra lines to get heading
csv$ = left$(csv$,k - 1) + " + mid$(csv$,k + 1) csv$ = strRep$(csv$,",","") html "
</table"wait ' -------------------------------- ' string replace rep str with ' -------------------------------- FUNCTION strRep$(strRep$,rep$,with$) ln = len(rep$) k = instr(strRep$,rep$) while k strRep$ = left$(strRep$,k - 1) + with$ + mid$(strRep$,k + ln) k = instr(strRep$,rep$) WEND END FUNCTION</lang>
- Output:
";strRep$(csv$,chr$(13)," |
---|
");" |
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! |
Rust
<lang rust>static INPUT : &'static str = "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!";
fn main() {
print!("
\n\n\n");
for c in INPUT.chars() { match c {'\n' => print!(" | |
"), ',' => print!(" | "),
'<' => print!("<"), '>' => print!(">"), '&' => print!("&"), _ => print!("{}", c) } }println!(" |
");
} </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>
Scala
Scala has built-in support for XML, so you can freely mix XML literals into your Scala source code. This is nice, because instead of using strings to represent XML, you create XML literals that the compiler can understand and verify. This approach lets you easily generate dynamic XML by interweaving Scala code and XML in the same expressions.<lang scala>object CsvToHTML extends App {
val header = <head> <title>CsvToHTML</title> <style type="text/css"> td Template:Background-color: thead td Template:Background-color: </style> </head> val 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!""".stripMargin
def csv2html(csv: String, withHead: Boolean) = {
def processRow(text: String) = {text.split(',').map(s =>
{s}
)} val (first :: rest) = csv.lines.toList // Separate the header and the rest def tableHead = if (withHead) <thead> {processRow(first)} </thead> else processRow(first) <html> {header}<body>
{tableHead}{rest.map(processRow)}</body> </html> }
println(csv2html(csv, true))
}</lang>
- Output:
<lang html><html>
<head> <title>CsvToHTML</title> <style type="text/css"> td {background-color:#ddddff; } thead td {background-color:#ddffdd; text-align:center; } </style> </head><body><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! |
</body> </html></lang>
Sed
File csv2html.sed <lang sed>#!/bin/sed -f
s|<|\<|g s|>|\>|g
s|^| \n | s|,|\n | s|$|\n | 1s|^|
\n| $s|$|\n|</lang>
$ sed -f csv2html.sed input.csv
<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>
Seed7
The library html_ent.s7i defines the function encodeHtmlContent, which replaces characters with HTML entities. E.g.: '<' is replaced by <. <lang seed7>$ include "seed7_05.s7i";
include "html_ent.s7i";
const string: csvData is "\
\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";
const proc: main is func
local var string: line is ""; var string: column is "";
const array [boolean] string: columnStartTag is [boolean] ("", ""); const array [boolean] string: columnEndTag is [boolean] ("", ""); var boolean: firstLine is TRUE; begin writeln("
"); for line range split(csvData, '\n') do write(""); for column range split(line, ',') do write(columnStartTag[firstLine] <& encodeHtmlContent(column) <& columnEndTag[firstLine]); end for; writeln(""); firstLine := FALSE; end for; writeln("");
end func;</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>
- Output:
viewed with a browser
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! |
Sidef
<lang ruby>func escape(str) { str.trans(« & < > », « & < > ») } func tag(t, d) { "<#{t}>#{d}</#{t}>" }
func csv2html(str) {
var template = <<-'EOT' <!DOCTYPE html> <html> <head><title>Some Text</title></head>
<body>
%s</body></html>
EOT
template.sprintf(escape(str).lines.map{ |line| tag('tr', line.split(',').map{|cell| tag('td', cell) }.join) }.join("\n") )
}
var str = <<'EOT'; 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! EOT
print csv2html(str)</lang>
- Output:
<lang html5><!DOCTYPE html> <html> <head><title>Some Text</title></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>
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)
TXR
Simple
<lang txr>@(collect) @char,@speech @(end) @(output :filter :to_html)
@ (repeat) @ (end)@char | @speech |
@(end)</lang>
- Output:
$ txr csv.txr csv.txt
<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>
With Styling
<lang txr>@(collect) @char,@speech @(end) @(output :filter :to_html) <style type="text/css"> tr.odd td {
background-color: #CC9999; color: black;
} tr.even td {
background-color: #9999CC; color: black;
} th {
background-color: #99CC99; color: black;
} </style>
@ (repeat :counter row) @ (first) @ (end)@char | @speech |
@char | @speech |
---|
@(end)</lang>
- Output:
$ txr csv2.txr csv.txt
<lang html5><style type="text/css"> tr.odd td {
background-color: #CC9999; color: black;
} tr.even td {
background-color: #9999CC; color: black;
} th {
background-color: #99CC99; color: black;
} </style>
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>
UNIX Shell
<lang bash>csv2html() {
IFS=,
echo "
" echo "<thead>" read -r speaker text htmlrow "$speaker" "$text" th echo "</thead>" echo "<tbody>" while read -r speaker text; do htmlrow "$speaker" "$text" done echo "</tbody>" echo ""
}
htmlrow() {
cell=${3:-td}
printf "<%s>%s</%s><%s>%s</%s>\n" \ "$cell" "$(escape_html "$1")" "$cell" \ "$cell" "$(escape_html "$2")" "$cell" } escape_html() { str=${1//\&/&} str=${str//</<} str=${str//>/>} echo "$str" } html=$( csv2html <<-END 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! END ) echo "$html"</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>
VBA
<lang vb>Public Sub CSV_TO_HTML()
input_ = "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!"
Debug.Print "
" & vbCrLf & "" & vbCrLf & "" & vbCrLf & ""
For i = 1 To Len(input_) Select Case Mid(input_, i, 1) Case "\" If Mid(input_, i + 1, 1) = "n" ThenDebug.Print " | |
";
i = i + 1 Else Debug.Print Mid(input_, i, 1); End IfCase ",": Debug.Print " | ";
Case "<": Debug.Print "<"; Case ">": Debug.Print ">"; Case "&": Debug.Print "&"; Case Else: Debug.Print Mid(input_, i, 1); End Select Next iDebug.Print " |
" End Sub</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>
VBScript
<lang vb> Set objfso = CreateObject("Scripting.FileSystemObject")
parent_folder = objfso.GetParentFolderName(WScript.ScriptFullName) & "\"
Set objcsv = objfso.OpenTextFile(parent_folder & "in.csv",1,False) Set objhtml = objfso.OpenTextFile(paren_folder & "out.html",2,True)
objhtml.Write(csv_to_html(objcsv.ReadAll))
objcsv.Close objhtml.Close Set objfso = Nothing
Function csv_to_html(s) row = Split(s,vbCrLf) 'write the header
tmp = "<html><head><head/><body>
" For i = 0 To UBound(row) field = Split(row(i),",") If i = 0 Then tmp = tmp & ""Else
tmp = tmp & ""End If Next 'write the footer
tmp = tmp & "" & replace_chars(field(0)) & " | " & replace_chars(field(1)) & " |
---|---|
" & replace_chars(field(0)) & " | " & replace_chars(field(1)) & " |
</body></html>"
csv_to_html = tmp End Function
Function replace_chars(s) replace_chars = Replace(Replace(s,"<","<"),">",">") End Function </lang>
- Output:
Format derived from BBC BASIC 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! |
Vedit macro language
This solution converts the table in-place in current edit buffer. If a block is highlighted, only the block is converted. If no block highlighted, the entire file is converted.
<lang vedit>if (BB < 0) { // block not set
BB(0) // convert entire file BE(File_Size)
}
// Convert special characters into entities Replace_Block("&","&", BB, BE, BEGIN+ALL+NOERR) Replace_Block("<","<", BB, BE, BEGIN+ALL+NOERR) Replace_Block(">",">", BB, BE, BEGIN+ALL+NOERR)
// Convert CSV into HTML table Goto_Pos(BB)
IT('
') IN- 80 = Cur_Pos
")
- 81 = Cur_Line
IN Goto_Pos(#80) while (Cur_Line < #81) {
IT(" ") Replace_Block(",","",Cur_Pos,EOL_Pos,ALL+NOERR)
EOL
IT("") Line(1) } BB(Clear)</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>
Visual Basic .NET
Uses XML literals and the TextFieldParser class of the VB runtime, which can parse delimited or fixed-width files.
The optional first command-line argument denotes whether to use <thead /> for the first row. The optional second argument specifies the path of the CSV file. If no second argument is given, the program reads from the console until stop characters are encountered.
TextFieldParser is designed to work with files and so makes heavy use of peeking, which results in buggy behavior when signaling end-of-file using the console. The most reliable way seems to be alternately pressing enter and Ctrl+Z after the last character of the last line of data.
<lang vbnet>Imports Microsoft.VisualBasic.FileIO
Module Program
Sub Main(args As String()) Dim parser As TextFieldParser Try If args.Length > 1 Then parser = My.Computer.FileSystem.OpenTextFieldParser(args(1), ",") Else parser = New TextFieldParser(Console.In) With {.Delimiters = {","}} End If
Dim getLines = Iterator Function() As IEnumerable(Of String()) Do Until parser.EndOfData Yield parser.ReadFields() Loop End Function
Dim result = CSVTOHTML(getLines(), If(args.Length > 0, Boolean.Parse(args(0)), False))
Console.WriteLine(result) Finally If parser IsNot Nothing Then parser.Dispose() End Try End Sub
Function CSVTOHTML(lines As IEnumerable(Of IEnumerable(Of String)), useTHead As Boolean) As XElement
Dim getRow = Function(row As IEnumerable(Of String)) From field In row Select <%= field %>
CSVTOHTML =<%= From l In lines.Select( Function(line, i) If useTHead AndAlso i = 0 Then Return <thead><%= getRow(line) %></thead> Else Return <%= getRow(line) %> End If End Function) %>
End Function
End Module</lang>
- Output — for input
true
:
<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! ^Z ^Z
<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>
XSLT 2.0
Setup
- Download to a local copy of the csv-to-xml.xslt library style-sheet listed in the linked blog entry. Alternatively a copy of the style-sheet on this wiki can be found here: csv-to-xml.xslt
- Pass as the URI of the input csv as a parameter (named url-of-csv) to your XSLT 2.0 processor
<lang><xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xcsvt="http://www.seanbdurkin.id.au/xslt/csv-to-xml.xslt" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xcsv="http://www.seanbdurkin.id.au/xslt/xcsv.xsd" version="2.0" exclude-result-prefixes="xsl xs xcsvt xcsv"> <xsl:import href="csv-to-xml.xslt" /> <xsl:output indent="yes" encoding="UTF-8" method="html" doctype-system="about:legacy-compat" /> <xsl:import-schema schema-location="http://www.seanbdurkin.id.au/xslt/xcsv.xsd" use-when="system-property('xsl:is-schema-aware')='yes'" /> <xsl:param name="url-of-csv" as="xs:string" select="'roseta.csv'" />
<xsl:variable name="phase-1-result"> <xsl:call-template name="xcsvt:main" /> </xsl:variable>
<xsl:template match="/"> <html lang="en"> <head><title>CSV to HTML translation - Extra Credit</title></head> <body> <xsl:apply-templates select="$phase-1-result" mode="phase-2" /> </body> </html> </xsl:template>
<xsl:template match="xcsv:comma-separated-single-line-values" mode="phase-2"><xsl:apply-templates mode="phase-2" />
</xsl:template>
<xsl:template match="xcsv:row[1]" mode="phase-2">
<xsl:apply-templates mode="phase-2" />
</xsl:template> <xsl:template match="xcsv:row" mode="phase-2"> <xsl:apply-templates mode="phase-2" /> </xsl:template> <xsl:template match="xcsv:value" mode="phase-2">
<xsl:apply-templates mode="phase-2" />
</xsl:template> <xsl:template match="xcsv:notice" mode="phase-2" /> </xsl:stylesheet></lang> This style-sheet, when applied to the task input, yields... <lang html5><!DOCTYPE html SYSTEM "about:legacy-compat"> <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>CSV to HTML translation - Extra Credit</title> </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>
zkl
<lang zkl>csvData:=Data(0,Int,"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!");
html:=csvData.pump("
\n",fcn(line){ line.replace("&","&").replace("<","<") // <angry/> --> <angry/> .split(",") .pump("\n","strip",String.fpM("101"," \n"))+"\n" }) + ""," |
";
html.println();</lang>
The pump method writes or appends to a sink, in this case a string (eg "
"). The fpM method is function/partial application and takes a string (ones and zeros) to indicate the positional input parameters. So String.fpM("101","a","c")("B") creates a new string "aBc".- 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! |
</lang>
- Programming Tasks
- Solutions by Programming Task
- 11l
- Ada
- AWS
- ALGOL 68
- AutoHotkey
- AutoIt
- ANTLR
- AWK
- Batch File
- BBC BASIC
- Bracmat
- Befunge
- C
- C++
- C sharp
- CoffeeScript
- Clojure
- Common Lisp
- D
- Delphi
- EchoLisp
- Erlang
- Euphoria
- F Sharp
- Factor
- Forth
- Fortran
- Go
- Groovy
- Haskell
- Icon
- Unicon
- J
- Java
- JavaScript
- Jq
- Jsish
- Julia
- Kotlin
- Liberty BASIC
- Lua
- Maple
- Mathematica
- Wolfram Language
- MATLAB
- Maxima
- ML/I
- Nanoquery
- NetRexx
- Nim
- Oberon-2
- Objeck
- OCaml
- OpenEdge/Progress
- Perl
- Perl 6
- Phix
- PHP
- PicoLisp
- PowerShell
- Prolog
- Python
- R
- Racket
- Red
- Retro
- REXX
- Ruby
- Run BASIC
- Rust
- Scala
- Org.scala-lang.xml
- Sed
- Seed7
- Sidef
- Tcl
- Tcllib
- TUSCRIPT
- TXR
- UNIX Shell
- VBA
- VBScript
- Vedit macro language
- Visual Basic .NET
- XSLT 2.0
- Zkl