Konverter CSV ke HTML

Sep 08 2020

Saya telah menulis sebuah program kecil yang mengubah CSV-File menjadi HTML-Table. Ini bekerja untuk tujuan saya. Tetapi apakah ada bagian dalam kode saya yang dapat ditulis lebih bersih? Bisakah Anda meningkatkan kinerja? Apakah mungkin ada bug? Saya mencari bug dan untungnya saya tidak menemukan beberapa.

Nota bene

Mungkin saya harus memberikan beberapa informasi latar belakang: Saya sedang mengerjakan dokumentasi database yang saya tulis sebagai dokumen HTML, karena saya tidak suka dokumen Word. Namun, membuat deskripsi tabel dari kolom dengan lusinan tag itu menyakitkan. Itulah mengapa saya menulis skrip ini: Sekarang saya hanya perlu mengekspor informasi tabel sebagai CSV dan dapat mengubahnya secara langsung tanpa harus memasukkan sendiri banyak tag. Inilah sebabnya mengapa tidak ada tag HTML dan badan: Tabel yang dibuat tidak boleh menjadi dokumen HTML terpisah, tetapi bagian dari satu dokumen HTML besar.

CsvToHtmlTable.java

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.FileWriter;
import java.util.List;
import java.util.ArrayList;

public class CsvToHtmlTable {
    public static void main(String[] args) {
        // print info and show user how to call the program if needed
        System.out.println("This program is tested only for UTF-8 files.");
        if (args[0].equalsIgnoreCase("help") || args[0].equalsIgnoreCase("-help") || args.length != 2) {
            System.out.println("java CsvToHtmlTable <input file> <output file>");
            System.out.println("Example: java CsvToHtmlTable nice.csv nice.html");
            System.exit(0);
        }
        
        String csvFile = args[0];
        String outputFile = args[1];
        
        // read lines of csv to a string array list
        List<String> lines = new ArrayList<String>();
        try (BufferedReader reader = new BufferedReader(new FileReader(csvFile))) {
            String currentLine;
            while ((currentLine = reader.readLine()) != null) {
                lines.add(currentLine);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        //embrace <td> and <tr> for lines and columns
        for (int i = 0; i < lines.size(); i++) {
            lines.set(i, "<tr><td>" + lines.get(i) + "</td></tr>");
            lines.set(i, lines.get(i).replaceAll(",", "</td><td>"));
        }
        
        // embrace <table> and </table>
        lines.set(0, "<table border>" + lines.get(0));
        lines.set(lines.size() - 1, lines.get(lines.size() - 1) + "</table>"); 
        
        // output result
        try (FileWriter writer = new FileWriter(outputFile)) {
            for (String line : lines) {
                writer.write(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Bagaimana memanggil program:

java CsvToHtmlTable ExampleInput.csv ExampleOutput.html

ExampleInput.csv

Name,Vorname,Alter
Ulbrecht,Klaus Dieter,12
Meier,Bertha,102

ExampleOutput.html

<table border><tr><td>Name</td><td>Vorname</td><td>Alter</td></tr>
<tr><td>Ulbrecht</td><td>Klaus Dieter</td><td>12</td></tr>
<tr><td>Meier</td><td>Bertha</td><td>102</td></tr></table>

Jawaban

4 Marc Sep 09 2020 at 03:25

Penerapan yang bagus, temukan saran saya sebaris.


bisa ditulis lebih bersih?

  • Kelas java.nio.file.Filesmemiliki beberapa metode praktis yang dapat Anda gunakan:
lines = Files.readAllLines(Paths.get(csvFile), StandardCharsets.UTF_8);
//..
Files.write(Paths.get(outputFile), lines);
  • Pertimbangkan untuk membuat konstanta untuk karakter pembatas. Beberapa file CSV dibatasi oleh ;untuk menangani nilai yang mengandung koma, dll .:
public static final String DELIMITER_CHAR=",";
  • Berikan pesan pengguna dan keluar jika ada Pengecualian I / O, misalnya:
} catch (IOException e) {
    System.out.println("Error reading input file: "+e.getMessage());
    System.exit(1);
}
  • Enkapsulasi logika untuk mengubah garis menjadi metode, sehingga lebih mudah untuk menguji dan menggunakan kembali. Sebagai contoh:
public class CsvToHtmlTable{
    public static List<String> convert(List<String> lines){/**/}
    public static void main(String[] args){/**/}
}

Bisakah Anda meningkatkan kinerja?

Batasan implementasi ini adalah batasan memori. Jika file masukan besar, seluruh file mungkin tidak muat di memori yang tersedia.

Mungkin bukan kasus Anda, tetapi jika Anda perlu menangani file besar, pertimbangkan membaca dan menulis file baris demi baris.


Apakah mungkin ada bug?

  • Periksa apakah file input kosong, jika lines.set(0,..)tidak gagal
  • Seperti yang disebutkan @ Doi9t, logika validasi input perlu dipertimbangkan ketika tidak ada argumen, satu, dua atau lebih.
5 AJNeufeld Sep 09 2020 at 03:02

CSVReader

Membaca file CSV bisa menjadi tugas yang rumit. Meskipun banyak file CSV hanya berupa nilai yang dipisahkan koma, jika nilai berisi koma, nilai tersebut akan diapit oleh tanda kutip ganda, dan jika nilai tersebut berisi tanda kutip ganda, tanda kutip ganda itu sendiri digandakan.

Untuk menangani ini lebih dari sekadar file CSV dasar, Anda benar-benar harus menggunakan pustaka CSV, seperti OpenCSV (com.opencsv: opencsv: 5.0) atau Apache Commons CSV (org.apache.commons: commons-csv: 1.7).

HTML

HTML yang valid

Kode Anda pada dasarnya hanya menulis <table>...table data...</table>. Ini bukan HTML yang benar. Anda kehilangan <html>...</html>tag di sekitar seluruh dokumen, dan di <body>...</body>sekitar konten. Anda mungkin juga harus memiliki <head>...</head>, mungkin dengan yang bagus <title>...</title>.

Lolos

Jika data yang CSV Anda berisi karakter khusus, seperti <, >, dan &, Anda benar-benar harus melarikan diri mereka dalam tabel HTML yang dihasilkan.

Judul Tabel

Sepertinya baris pertama tabel Anda berisi judul, bukan data. Baris tabel pertama mungkin harus diformat dengan <th>...</th>tag, bukan <td>...</td>tag.

Pemrosesan baris demi baris

Anda membaca seluruh file CSV ke dalam memori, dan hanya jika telah dimuat secara keseluruhan Anda dapat menuliskannya kembali sebagai HTML. Ini sangat menguras memori, terutama jika file CSV berukuran besar!

Sebaliknya, Anda dapat:

  • buka CSV
  • buka file HTML
  • tulis prolog HTML
  • untuk setiap baris dibaca dari file CSV:
    • memformat dan menulis baris ke file HTML
  • tulis epilog HTML

Belum teruji, membuat kode dari awal, tanpa menangani kutipan dalam CSV atau keluar dari entitas HTML apa pun dalam keluaran:

        try (BufferedReader reader = new BufferedReader(new FileReader(csvFile));
             FileWriter writer = new FileWriter(outputFile)) {

            writer.write("<html><body><table border>\n");

            String currentLine;
            while ((currentLine = reader.readLine()) != null) {
                writer.write("<tr>");

                for(String field: currentLine.split(","))
                    writer.write("<td>" + field + "</td>");

                writer.write("</tr>\n");
            }

            writer.write("</table></body></html>\n");

        } catch (IOException e) {
            e.printStackTrace();
        }

XML & XSLT

Anda mungkin ingin mempertimbangkan untuk membuat penerjemah CSV ke XML.

Output XML Anda mungkin terlihat seperti:

<data input-file='ExampleInput.csv'>
  <person>
    <Name>Ulbrecht</Name>
    <Vorname>Klaus Dieter</Vorname>
    <Alter>12</Alter>
  </person>
  <person>
    <Name>Meier</Name>
    <Vorname>Bertha</Vorname>
    <Alter>102</Alter>
  </person>
</data>

Dan kemudian Anda dapat menggunakan XSLT Stylesheet untuk menerjemahkan XML ke HTML, mungkin di browser tanpa pernah menulis HTML ke file.

3 Noname Sep 10 2020 at 23:23

Mungkin NullPointerExceptionsejalanif (args[0].equals...

Harap periksa argsukuran input dan nullifyingsebelum melanjutkan untuk mengakses indeks / item apa pun.
Ya, itu argsbisa jadi null, seperti yang dipanggil oleh kelas lain yang dimuat. Atau kosong, jika pengguna lupa menyetel args.

File Penyangga

Saya pikir menyimpan seluruh file dalam memori, dan kemudian memprosesnya adalah ide yang bagus untuk kasus Anda, karena setiap baris yang Anda baca, Anda cukup memproses, dan menulisnya, dan melanjutkan ke baris berikutnya. (seperti Line By Line Processing yang disebutkan oleh AJNeufeld)

Pemisahan Kolom Rusak (pembatas)

Pada dasarnya, pemisahan data kolom menggunakan lines.get(i).replaceAll(",",...)rusak, karena data itu sendiri akan memiliki ,konten.

Mempertimbangkan baris sebagai Porsche,"991,991.2,992",70tempat kode Anda (dan bahkan yang disediakan oleh AJNeufeld) akan gagal, karena 991,991.2,992adalah satu nilai, dan nilai ""tersebut ada untuk memberi tahu parser, data yang lolos ada di depan.

Jadi secara pribadi, saya sarankan untuk melakukan proses parsing char-by-char, yang memungkinkan Anda melewatkan apa pun ,sebagai pembatas ketika Anda mencapai pembukaan "hingga "pasangan akhirnya .

Karakter Tak Terduga

Juga mempertimbangkan untuk menegaskan, melewati, atau mengonversi karakter yang tidak terduga. Misalnya mengubah a NULL( \0) char menjadi 0x00atau menampilkan peringatan dan melewatkannya.

Lupakan File

Saya sarankan, untuk tidak mengunci aplikasi Anda hanya untuk membaca dari file, dan menyimpannya. Berkali-kali STDIN, dan STDOUTcara yang lebih diterima.

Saya menyarankan untuk mendukung dari file dan STDIN. Misalnya, gunakan harus disetel -finuntuk input file dalam argumen, atau -stdinuntuk menginformasikan alat yang dibaca STDIN.

Memeriksa File

Memeriksa file (baik masuk / keluar) sebelum memproses file juga akan bagus. Untuk memastikannya dapat diakses.

Tuntutan

Membersihkan (atau meminta / mengatur) hasilnya, sementara ada pengecualian IO yang tidak terduga selama proses bisa jadi bagus juga.

Semoga membantu.