24

I am trying to convert this HTML table:

enter image description here

Code:

<table id="students" border="1">
    <thead>
        <tr>
            <th>Name</th>
            <th>Age</th>
            <th>Grade</th>
        </tr>
    </thead>
    <tbody>
        <tr class="student">
            <td>Oscar</td>
            <td>23</td>
            <td>16.5</td>        
        </tr>
        <tr class="student">
            <td>Antonio</td>
            <td>32</td>
            <td>14</td>        
        </tr>
        <tr class="student">
            <td>Jessica</td>
            <td>21</td>
            <td>19</td>        
        </tr>
    </tbody>
</table>​​​​​​

Into a javascript object using jQuery:

var tbl = $('table#students tr').map(function() {
  return $(this).find('td').map(function() {
    return $(this).text();
  }).get();
}).get();

The above code will output the following array:

["Oscar", "23", "16.5", "Antonio", "32", "14", "Jessica", "21", "19"]

Everything is good at this point but how can I do if I want the javascript objects inside the array to have the following structure:

[{id:1, name: "Oscar", age: 23, grade: 16.5}, {id:2, name: "Antonio", age: 32, grade: 14}, {id:3, name: "Jessica", age: 21, grade: 19}]

enter image description here

Just to be more specific...

  • The id is obtained from the tr
  • The name, age and grade values are obtained from each row

I made this jsfiddle to test:

http://jsfiddle.net/oscarj24/ptVDm/

Thanks

Ben Aubin
  • 5,542
  • 2
  • 34
  • 54
Oscar Jara
  • 14,129
  • 10
  • 62
  • 94
  • 1
    The second example is **NOT JSON**. It's a **JavaScript object**. Too many people are confused already about what JSON is, so I'm going to be picky and point this out. – Aesthete Sep 05 '12 at 23:26
  • it's so simple but i must say i needed some time myself to get it right: JSON is a serialization ('stringification') format. if it's not a string, it's not JSON; if it's a string, it may or may not parse as valid JSON. when someone says 'a JSON object', then what they might mean is 'a data value that is readily serialized as JSON' (which is not true for all values). – flow Nov 27 '14 at 13:43
  • Does this answer your question? [Convert a HTML table data into a JSON object in jQuery](https://stackoverflow.com/questions/2240005/convert-a-html-table-data-into-a-json-object-in-jquery) – Heretic Monkey Jun 23 '20 at 19:00

6 Answers6

33
var tbl = $('#students tr:has(td)').map(function(i, v) {
    var $td =  $('td', this);
        return {
                 id: ++i,
                 name: $td.eq(0).text(),
                 age: $td.eq(1).text(),
                 grade: $td.eq(2).text()               
               }
}).get();

Ram
  • 143,282
  • 16
  • 168
  • 197
10

I needed this exact thing, except I needed more features to be able to override column names and ignore any hidden rows. I wrote a jQuery plugin that does just that, located here https://github.com/lightswitch05/table-to-json

for your example you would do: (http://jsfiddle.net/ptVDm/118/)

var table = $('#students').tableToJSON();

One thing to note is that the id's aren't part of the resulting object. You could just get the id from the object's array location. Or if you really needed it to be part of the object, you could create an hidden column for the ID's and then they would be included

lightswitch05
  • 9,058
  • 7
  • 52
  • 75
  • There is an issue with this approach when you are going to use `rowspan` or `colspan` in table. For normal table, it is perfectly ok. – D3V Mar 26 '14 at 08:23
  • @D3V - You are right, I haven't added any support for `rowspan` or `colspan`. You are more then welcome to add support and I'll merge the changes if you like – lightswitch05 Mar 26 '14 at 14:35
  • @lightswitch05: I had one requirement where I needed to take them into consideration. I calculated the index of each attribute-value on the go and had a cache to store them and carry forward those values so that all the keys can be properly aligned with column name. I will try to make that code more generic and merge it with the plugin. – D3V Mar 27 '14 at 19:02
  • 2
    @D3V The table-to-json plugin has been updated to work with `rowspan` and `colspan`, it includes support for hidden columns & rows as well ([demo](http://jsfiddle.net/Mottie/4E2L6/11/)). – Mottie Apr 17 '14 at 16:07
8

The following should work:

var cols = [];
var result = [];
$('#students>thead>th').each(function(){
    cols.push($(this).text().toLowerCase());
});
$('#students>tbody>tr').each(function(id){
    var row = {'id': id+1};
    $(this).find('td').each(function(index){
        row[cols[index]] = $(this).text();
    });
    result.push(row);
});

console.log(result);

Basically, I find the object properties from the table head, next I create an object for each row, assigning values to property names as deduced from the earlier array.

Some obvious flaws:

  • If the table data actually differs for some reason, (eg; empty rows for cosmetic), this system will put empty objects in the resulting array.
  • If you use colspan attribute in the table, this system won't automatically replicate the same value in different object properties, but rather limit to setting up to the remaining <td>s.

Seeing Josiah's approach, it's probably faster than mine since mine tries to be smarter by finding property names. I would recommend his technique if you know for sure your table structure will not change. Otherwise, you would need something on the lines of my code.

Oh, and for the sake of completeness, here's a JSFiddle with mine.

Christian
  • 27,509
  • 17
  • 111
  • 155
4

See updated fiddle. The additional array map is unnecessary because you are looking for a literal object for your JSON at this point.

var data = $('table#students tbody tr').map(function(index) {
    var cols = $(this).find('td');
    return {
        id: index + 1,
        name: cols[0].innerHTML,            // use innerHTML
        age: (cols[1].innerHTML + '') * 1,  // parse int
        grade: (cols[2].innerHTML + '') * 1 // parse int
    };
}).get();
Josiah Ruddell
  • 29,697
  • 8
  • 65
  • 67
2

Dunno if jQuery helps much in this case, here's a plain JS solution that is reasonably independent of the table structure. It just requires that the first row is a header (can be a different table section element or not) and the rows 1+ are data.

The table can have as many columns or rows as you like, if there are rowspan or colspans in there it will mess with the result (but jQuery won't help you with that either).

It could easily be adapted to specifically use the header section for the property names and to ignore a footer section:

function tableToObj(table) {
  var rows = table.rows;
  var propCells = rows[0].cells;
  var propNames = [];
  var results = [];
  var obj, row, cells;

  // Use the first row for the property names
  // Could use a header section but result is the same if
  // there is only one header row
  for (var i=0, iLen=propCells.length; i<iLen; i++) {
    propNames.push(propCells[i].textContent || propCells[i].innerText);
  }

  // Use the rows for data
  // Could use tbody rows here to exclude header & footer
  // but starting from 1 gives required result
  for (var j=1, jLen=rows.length; j<jLen; j++) {
    cells = rows[j].cells;
    obj = {};

    for (var k=0; k<iLen; k++) {
      obj[propNames[k]] = cells[k].textContent || cells[k].innerText;
    }
    results.push(obj)
  }
  return results;
}
RobG
  • 142,382
  • 31
  • 172
  • 209
1

Try below approach for n columns

DEMO: http://jsfiddle.net/ptVDm/7/

var tblhdr = $('table#students th').map(function () {
    return $(this).text();
}).get();

console.log(tblhdr);

var tbl = $('table#students tbody tr').map(function(idx, el) {
    var td = $(el).find('td');
    var obj = {id: idx+1};

    //Can work on number of columns
    for (var i = 0; i < tblhdr.length; i++) {
        obj[tblhdr[i]] = td.eq(i).text();
    }

    return obj;
}).get();

console.log(tbl);
Selvakumar Arumugam
  • 79,297
  • 15
  • 120
  • 134