Translate CSV To HTML
January 15, 2013
The text-file database library makes this task simple: We write a write-html-rec
function similar to the other writers, then use for-each-port
to perform the conversion. Here’s write-html-rec
:
(define (write-html-record rec)
(display "<tr>")
(for-each
(lambda (field)
(display "<td>")
(display field)
(display "</td>"))
rec)
(display "</tr>")
(newline))
Each record forms a single line, with an initial <tr>
and final </tr>
. Each field within the record is written with an initial <td>
and final </td>
. This function is called in the csv->html
function, which reads from the current-input-port
and writes to the current-output-port
:
(define (csv->html)
(display "<table>")
(newline)
(for-each-port
read-csv-record
write-html-record)
(display "</table>")
(newline))
Here we give the initial <table>
and final </table>
, then use for-each-port
to structure the processing.
We use the same emp.data
sample file as the essay, with help from the string-join
function of the Standard Prelude:
(define emp-data-csv
(string-join #\newline
'("Beth,12.75,0,mfg"
"Dan,8.50,10,sales"
"Kathy,11.40,30,sales"
"Mark,12.75,40,mfg"
"Mary,7.50,20,mfg"
"Susie,10.30,25,acctg")))
That can be converted to HTML like this:
(define emp-data-html
(with-input-from-string
emp-data-csv
(lambda ()
(with-output-to-string
(lambda ()
(csv->html))))))
The resulting output, folded at newlines, contains all the markup for an HTML table:
<table>\n
<tr><td>Beth</td><td>12.75</td><td>0</td><td>mfg</td></tr>\n
<tr><td>Dan</td><td>8.50</td><td>10</td><td>sales</td></tr>\n
<tr><td>Kathy</td><td>11.40</td><td>30</td><td>sales</td></tr>\n
<tr><td>Mark</td><td>12.75</td><td>40</td><td>mfg</td></tr>\n
<tr><td>Mary</td><td>7.50</td><td>20</td><td>mfg</td></tr>\n
<tr><td>Susie</td><td>10.30</td><td>25</td><td>acctg</td></tr>\n
</table>\n
Rendered in a browser, it looks like this:
Beth | 12.75 | 0 | mfg |
Dan | 8.50 | 10 | sales |
Kathy | 11.40 | 30 | sales |
Mark | 12.75 | 40 | mfg |
Mary | 7.50 | 20 | mfg |
Susie | 10.30 | 25 | acctg |
Our HTML is purposely simple-minded. You are welcome to add borders or other formatting, to treat the first line of the file as column headers, or make other changes to suit your needs.
You can run the program at http://programmingpraxis.codepad.org/ug3oKyMJ.
[…] today’s Programming Praxis exercise, our goal is to translate a csv file to an HTML table. Let’s get […]
My Haskell solution (see http://bonsaicode.wordpress.com/2013/01/15/programming-praxis-translate-csv-to-html/ for a version with comments):
[…] Question is from here: […]
Java solution here.
Answer in awk (here)[http://psykotedy.tumblr.com/post/40602728216/programming-praxis-convert-csv-to-html].
Sorry for the sloppy comment, I don’t know the markup required for the comments here.
[…] Pages: 1 2 […]
Ruby solution
Doesn’t seem anyone other than Programming Praxis dealt with quoted strings
(which, granted, isn’t necessarily a part of ‘official’ CSV files). It does
make the code quite a bit more interesting if you do. :)
Anyways, here’s my short (ugly) version that doesn’t deal with quoted
strings:
And here’s a longer (more awesome!) version that correctly deals with
quotes and translates what it can to Scheme values (numbers, symbols,
#t/#f, etc): blog post
[…] post is a Python solution to a programming challenge from Programming Praxis. The challenge is to read a csv file and convert it into an html […]
Here’s a solution in PHP:
<?php
define("DIRECTORY", "./");
if (file_exists(DIRECTORY."x.txt")) {
$xfile = fopen(DIRECTORY."x.txt", "r");
$xcontent = fgetcsv($xfile);
echo "
“;
foreach ($xcontent as $xentry) {
echo “”.$xentry.””;
}
echo ”
“;
} else die(“The file does not exist.”);
?>
Quotation marks delineated with a q:
<?php
define("DIRECTORY", "./");
if (file_exists(DIRECTORY."x.txt")) {
$xfile = fopen(DIRECTORY."x.txt", "r");
$xcontent = fgetcsv($xfile);
echo q
q;
foreach ($xcontent as $xentry) {
echo qq.$xentry.qq;
}
echo q
q;
} else die(“The file does not exist.”);
?>
Third time is NOT a charm… :/
CSV To HTML
Using JSP
CSV To HTML
Python 3.3 solution. Uses the standard library csv to read the file and elementtree to build the table as an xml document. The tostring method takes care of properly escaping characters like <, if any, in the file.
import csv
import xml.etree.ElementTree as et
def csv2html(filelike_obj, id_=None):
table = et.Element(‘table’, {‘id’:id_} if id_ else {})
for n, line in enumerate(csv.reader(filelike_obj)):
row = et.SubElement(table, ‘tr’)
if n&1: row.set(‘class’, ‘odd’)
for item in line:
col = et.SubElement(row, ‘td’)
col.text = item
return et.tostring(table, method=’html’).decode()
Not sure what happened to the formatting above.
C#:
C#:
erdalkiran, few comments on your solution:
1. It generates 1-column table – for every comma in the source you produce a new row in the output. Instead it should produce a cell for every comma and a row for each newline.
2. I see no reason for manual buffered read in this case – you don’t process those chunks one by one, and in the end you still have a full raw string in memory, so why not use something like StreamReader.ReadToEnd() for simplicity?
3. I can’t see a practical reason for using StringBuilder to store the final output here. StringBuilder might save you memory allocations and some processor cycles if you have lots of string operations, true. But you only have 2 appends. Your code will still likely force a StringBuilder to allocate memory for its internal storage, perhaps more times than it would take to allocate 3 usual immutable strings in the first place.
Thus, I would suggest to implement your approach something like this: