Как преобразовать HTML-таблицу в Javascript Object с помощью jQuery

Я пытаюсь преобразовать эту таблицу HTML:

Код:

<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>​​​​​​

В объект javascript с использованием jQuery:

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

Приведенный выше код выведет следующий массив:

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

На данный момент все хорошо, но как я могу это сделать, если я хочу, чтобы объекты javascript внутри массива имели следующую структуру:

[{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}]

Просто чтобы быть более конкретным...

  • id получается из tr
  • name, age а также grade значения получены из каждой строки

Я сделал это jsfiddle для тестирования:

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

Спасибо

6 ответов

Решение
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();

Мне нужна была именно эта вещь, за исключением того, что мне нужно было больше возможностей, чтобы иметь возможность переопределять имена столбцов и игнорировать любые скрытые строки. Я написал плагин JQuery, который делает именно это, расположенный здесь https://github.com/lightswitch05/table-to-json

для вашего примера вы бы сделали: ( http://jsfiddle.net/ptVDm/118/)

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

Стоит отметить, что идентификаторы не являются частью результирующего объекта. Вы можете просто получить идентификатор из местоположения массива объекта. Или, если вам действительно нужно, чтобы он был частью объекта, вы можете создать скрытый столбец для идентификаторов, и тогда они будут включены

Следующее должно работать:

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);

По сути, я нахожу свойства объекта из заголовка таблицы, затем я создаю объект для каждой строки, присваивая значения именам свойств, как это было выведено из более раннего массива.

Некоторые очевидные недостатки:

  • Если данные таблицы действительно по какой-то причине отличаются (например, пустые строки для косметики), эта система поместит пустые объекты в результирующий массив.
  • Если вы используете colspan атрибут в таблице, эта система не будет автоматически реплицировать одно и то же значение в разных свойствах объекта, а ограничится настройкой оставшихся <td>s.

Видя подход Иосии, он, вероятно, быстрее моего, поскольку мой пытается быть умнее, находя имена свойств. Я бы порекомендовал его технику, если вы точно знаете, что структура вашего стола не изменится. В противном случае вам нужно что-то в строках моего кода.

Ох, и ради полноты, вот JSFiddle с моим.

Смотрите обновленную скрипку. Дополнительный массив map в этом нет необходимости, потому что вы ищете буквальный объект для вашего JSON.

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();

Не знаю, если jQuery очень помогает в этом случае, вот простое решение JS, которое достаточно независимо от структуры таблицы. Просто требуется, чтобы первая строка была заголовком (может быть другим элементом раздела таблицы или нет), а строки 1+ являются данными.

В таблице может быть столько столбцов или строк, сколько вам нужно, если в ней есть строки или столбцы, то это приведет к путанице с результатом (но jQuery вам в этом тоже не поможет).

Его можно легко адаптировать для специального использования раздела заголовка для имен свойств и игнорирования раздела нижнего колонтитула:

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;
}

Попробуйте ниже подход для n столбцов

ДЕМО: 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);
Другие вопросы по тегам