Integrar tabelas PDF com fontes de dados em Java

O exemplo em Java cria tabelas PDF a partir de dados CSV sem depender de bibliotecas externas de dataframes.

Criar uma tabela a partir de linhas CSV

Use este exemplo quando colunas CSV selecionadas devem ser transformadas em uma tabela PDF estilizada.

  1. Crie um Table e configure suas bordas.
  2. Detecte os índices de coluna necessários a partir da linha de cabeçalho CSV.
  3. Adicione a linha de cabeçalho e o número solicitado de linhas de dados, então retorne a tabela.
public static Table createTableFromCsv(List<String[]> rows, int maxRows) {
    Table table = new Table();
    table.setBorder(new BorderInfo(BorderSide.All, 1, Color.getLightGray()));
    table.setDefaultCellBorder(new BorderInfo(BorderSide.Bottom, 1, Color.getLightGray()));

    String[] header = rows.get(0);
    int[] selectedColumns = findColumns(header, "city", "country", "population", "iso3");

    Row headerRow = table.getRows().add();
    headerRow.setRowBroken(false);
    for (int columnIndex : selectedColumns) {
        Cell cell = headerRow.getCells().add(header[columnIndex]);
        cell.setBackgroundColor(Color.getLightGray());
    }

    int limit = Math.min(maxRows, rows.size() - 1);
    for (int rowIndex = 1; rowIndex <= limit; rowIndex++) {
        Row row = table.getRows().add();
        String[] rowData = rows.get(rowIndex);
        for (int columnIndex : selectedColumns) {
            row.getCells().add(columnIndex < rowData.length ? rowData[columnIndex] : "");
        }
    }

    return table;
}

Criar um PDF a partir de dados CSV

Use este exemplo quando a entrada CSV deve ser renderizada como um documento de tabela PDF.

  1. Leia as linhas CSV do arquivo de entrada.
  2. Visualize um subconjunto das linhas analisadas no console.
  3. Crie um PDF Document, adicione a tabela gerada, e salve o arquivo de saída.
public static void createPdfFromCsv(Path inputFile, Path outputFile, int maxRows) throws Exception {
    List<String[]> rows = readCsv(inputFile);
    for (int i = 0; i < Math.min(20, rows.size()); i++) {
        System.out.println(String.join(" | ", rows.get(i)));
    }

    try (Document document = new Document()) {
        Page page = document.getPages().add();
        page.getParagraphs().add(createTableFromCsv(rows, maxRows));
        document.save(outputFile.toString());
    }
}

Encontrar índices de colunas CSV por nome

Use este auxiliar quando colunas nomeadas específicas precisam ser localizadas na linha de cabeçalho do CSV.

  1. Itere pelos nomes de coluna solicitados.
  2. Pesquise a linha de cabeçalho em busca de índices correspondentes.
  3. Retorne as posições de coluna coletadas.
private static int[] findColumns(String[] header, String... names) {
    int[] indexes = new int[names.length];
    for (int i = 0; i < names.length; i++) {
        indexes[i] = 0;
        for (int j = 0; j < header.length; j++) {
            if (names[i].equals(header[j])) {
                indexes[i] = j;
                break;
            }
        }
    }
    return indexes;
}

Ler linhas CSV de um arquivo

Use este auxiliar quando a fonte CSV deve ser carregada na memória antes da geração da tabela.

  1. Leia todas as linhas do arquivo de entrada.
  2. Divida cada linha com o auxiliar de analisador CSV.
  3. Retorne os valores de linha coletados.
private static List<String[]> readCsv(Path inputFile) throws Exception {
    List<String[]> rows = new ArrayList<>();
    for (String line : Files.readAllLines(inputFile)) {
        rows.add(splitCsvLine(line));
    }
    return rows;
}

Dividir uma linha CSV em valores

Use este helper quando uma linha CSV pode conter valores entre aspas e caracteres de aspas escapados.

  1. Itere pelos caracteres na linha.
  2. Acompanhe se o analisador está atualmente dentro de texto entre aspas.
  3. Construa a lista final de valores e retorne-a como um array.
private static String[] splitCsvLine(String line) {
    List<String> values = new ArrayList<>();
    StringBuilder current = new StringBuilder();
    boolean inQuotes = false;
    for (int i = 0; i < line.length(); i++) {
        char ch = line.charAt(i);
        if (ch == '"') {
            if (inQuotes && i + 1 < line.length() && line.charAt(i + 1) == '"') {
                current.append('"');
                i++;
            } else {
                inQuotes = !inQuotes;
            }
        } else if (ch == ',' && !inQuotes) {
            values.add(current.toString());
            current.setLength(0);
        } else {
            current.append(ch);
        }
    }
    values.add(current.toString());
    return values.toArray(String[]::new);
}