Reputation: 39
I need to generate html table from 2d array containing only data, colspan and rowspan. I have no need for margins, heights and widths. Only td and tr. I know table cell width and height, result is always rectangular. I need to do it in java but any hint is welcome.
Here is an example cell class:
public class Cell {
String label;
int colSpan, rowSpan;
public Cell(String label, int colSpan, int rowSpan) {
this.label = label;
this.colSpan = colSpan;
this.rowSpan = rowSpan;
}
}
And here is an example of 2d array containing data and rowspan/colspan information;
public class Test {
public static void main(String[] args) {
List<List<Cell>> rows = new ArrayList<>();
List<Cell> row1 = new ArrayList<>();
Cell cell11 = new Cell("total", 1, 9);
Cell cell12 = new Cell("mid_total", 1, 3);
Cell cell13 = new Cell("detail", 1, 1);
row1.add(cell11);
row1.add(cell12);
row1.add(cell13);
rows.add(row1);
List<Cell> row2 = new ArrayList<>();
Cell cell21 = new Cell("mid_total", 1, 3);
Cell cell22 = new Cell("detail", 1, 1);
row2.add(cell21);
row2.add(cell22);
rows.add(row2);
List<Cell> row3 = new ArrayList<>();
Cell cell31 = new Cell("mid_total", 1, 3);
Cell cell32 = new Cell("detail", 1, 1);
row3.add(cell31);
row3.add(cell32);
rows.add(row3);
List<Cell> row4 = new ArrayList<>();
Cell cell41 = new Cell("detail", 1, 1);
row4.add(cell41);
rows.add(row4);
List<Cell> row5 = new ArrayList<>();
Cell cell51 = new Cell("detail", 1, 1);
row5.add(cell51);
rows.add(row5);
List<Cell> row6 = new ArrayList<>();
Cell cell61 = new Cell("detail", 1, 1);
row6.add(cell61);
rows.add(row6);
List<Cell> row7 = new ArrayList<>();
Cell cell71 = new Cell("detail", 1, 1);
row7.add(cell71);
rows.add(row7);
List<Cell> row8 = new ArrayList<>();
Cell cell81 = new Cell("detail", 1, 1);
row8.add(cell81);
rows.add(row8);
List<Cell> row9 = new ArrayList<>();
Cell cell91 = new Cell("detail", 1, 1);
row9.add(cell91);
rows.add(row9);
}
}
And here's how it should look like:
+-------+-----------+--------+
| total | mid_total | detail |
+ + +--------+
| | | detail |
+ + +--------+
| | | detail |
+ +-----------+--------+
| | mid_total | detail |
+ + +--------+
| | | detail |
+ + +--------+
| | | detail |
+ +-----------+--------+
| | mid_total | detail |
+ + +--------+
| | | detail |
+ + +--------+
| | | detail |
+-------+-----------+--------+
Upvotes: 1
Views: 2771
Reputation: 39
This is how my source rows look like, try it and see it yourself.
auto tbl = new Table();
tbl.newRow();
tbl.add("Total", 1, 9);
tbl.add("Subtotal A-C", 1, 3);
tbl.add("detail A");
tbl.newRow();
tbl.add("Subtotal D-F", 1, 3);
tbl.add("detail B");
tbl.newRow();
tbl.add("Subtotal G-I", 1, 3);
tbl.add("detail C");
tbl.newRow();
tbl.add("detail D");
tbl.newRow();
tbl.add("detail E");
tbl.newRow();
tbl.add("detail F");
tbl.newRow();
tbl.add("detail G");
tbl.newRow();
tbl.add("detail H");
tbl.newRow();
tbl.add("detail I");
writeln(tbl.toHtml());
Upvotes: 0
Reputation: 29126
You could create a container class for the cells, which manages the correct positioning of multi-column and multi-row cells.
You have a grid of slots and when you place a cell that span several columns or rows, you invalidate the slots that this big cell occupies, keeping a reference to the real cell only in the top left slot. When you print the markup, don't print invalidated cells.
You seem to create your tables top down, so a natural approach would be to keep track of the current row and columns, so that inserting a cell can find the next free one.
If you don't want to dimension the table beforehand or jiggle an ever-resizing grid of cells, you can store the cells in a hash map with their position in the grid as key, so that you can easily append cells without worrying to overflow the table.
An implementation with your example table is below. I'm not good with Java – I lack both the skills and the software – so I've writen the code in D. The principal idea should be clear, I think. D has associative arrays built in and V[K]
corresponds to Java's java.util.HashMap<K, V>
.
import std.stdio;
import std.array;
import std.string;
class Cell
{
public:
this(string _label, int _colSpan, int _rowSpan)
{
label = _label;
colSpan = _colSpan;
rowSpan = _rowSpan;
}
string toHtml() {
auto app = appender!string();
app.put(" <td");
if (colSpan > 1) app.put(format(" colspan='%d'", colSpan));
if (rowSpan > 1) app.put(format(" rowspan='%d'", rowSpan));
app.put(">");
app.put(label);
app.put("</td>\n");
return app.data;
}
private:
string label;
int colSpan;
int rowSpan;
}
class Table
{
public:
this() {
}
void newRow() {
row++;
col = 0;
}
void add(string label, int colSpan = 1, int rowSpan = 1)
{
assert(row >= 0);
assert(colSpan > 0);
assert(rowSpan > 0);
auto c = new Cell(label, colSpan, rowSpan);
while (key(col, row) in cell) col++;
for (int j = 0; j < rowSpan; j++) {
for (int i = 0; i < colSpan; i++) {
addCell(col + i, row + j,
(i == 0 && j == 0) ? c : null);
}
}
col += colSpan;
}
string toHtml() {
auto app = appender!string();
app.put("<table>\n");
for (int y = 0; y < nrow; y++) {
app.put(" <tr>\n");
for (int x = 0; x < ncol; x++) {
if (key(x, y) !in cell) {
app.put(" <td></td>\n");
} else {
Cell c = cell[key(x, y)];
if (c) app.put(c.toHtml());
}
}
app.put(" </tr>\n");
}
app.put("</table>");
return app.data;
}
private:
void addCell(int x, int y, Cell c) {
Cell *p = key(x, y) in cell;
if (x + 1 > ncol) ncol = x + 1;
if (y + 1 > nrow) nrow = y + 1;
assert(p is null);
cell[key(x, y)] = c;
}
static uint key(uint x, uint y)
{
const offset = 1u << 16;
return y * offset + x;
}
Cell[uint] cell; // map of positions to cells
int row = -1; // current row
int col; // current column
int nrow; // number of rows
int ncol; // number of columns
};
void main()
{
auto tbl = new Table();
tbl.newRow();
tbl.add("Total", 1, 9);
tbl.add("Subtotal A-C", 1, 3);
tbl.add("detail A");
tbl.newRow();
tbl.add("detail B");
tbl.newRow();
tbl.add("detail C");
tbl.newRow();
tbl.add("Subtotal D-F", 1, 3);
tbl.add("detail D");
tbl.newRow();
tbl.add("detail E");
tbl.newRow();
tbl.add("detail F");
tbl.newRow();
tbl.add("Subtotal G-I", 1, 3);
tbl.add("detail G");
tbl.newRow();
tbl.add("detail H");
tbl.newRow();
tbl.add("detail I");
writeln(tbl.toHtml());
}
Upvotes: 0
Reputation: 4039
iterate your rows and columns in your 2d array and create the HTML tags using a StringBuilder
.
public String toHTML(String[][] data){
StringBuilder sb = new StringBuilder();
sb.append("<table>\n");
for(int row = 0; row < data.length; row++){
sb.append("\t<tr>\n");
for(int col = 0; col < data[0].length; col++){
sb.append("\t\t<td>" + data[row][col] + "</td>\n");
}
sb.append("\t</tr>\n");
}
sb.append("</table>");
return sb.toString();
}
If you use it like this:
String[][] data = {{"r0c1", "r0c2", "r0c3"},
{"r1c1", "r1c2", "r1c3"}};
System.out.println(toHTML(data));
It will produce this:
<table>
<tr>
<td>r0c1</td>
<td>r0c2</td>
<td>r0c3</td>
</tr>
<tr>
<td>r1c1</td>
<td>r1c2</td>
<td>r1c3</td>
</tr>
</table>
Upvotes: 1