Генерация HTML-таблицы из массива хэшей в Ruby - PullRequest
11 голосов
/ 14 апреля 2010

Каков наилучший способ (в идеале, гем, но при необходимости фрагмент кода) генерировать таблицу HTML из массива хешей?

Например, этот массив хэшей:

[{"col1"=>"v1", "col2"=>"v2"}, {"col1"=>"v3", "col2"=>"v4"}]

Должен произвести эту таблицу:

<table>
  <tr><th>col1</th><th>col2</th></tr>
  <tr><td>v1</td><td>v2</td></tr>
  <tr><td>v3</td><td>v4</td></tr>
</table>

Ответы [ 6 ]

12 голосов
/ 11 октября 2013
# modified from Harish's answer, to take care of sparse hashes:

require 'builder'

def hasharray_to_html( hashArray )
  # collect all hash keys, even if they don't appear in each hash:
  headers = hashArray.inject([]){|a,x| a |= x.keys ; a}  # use array union to find all unique headers/keys                              

  html = Builder::XmlMarkup.new(:indent => 2)
  html.table {
    html.tr { headers.each{|h| html.th(h)} }
    hashArray.each do |row|
      html.tr { row.values.each { |value| html.td(value) }}
    end
  }
  return html
end
10 голосов
/ 14 апреля 2010

Используйте для этого XMLBuilder:

data = [{"col1"=>"v1", "col2"=>"v2"}, {"col1"=>"v3", "col2"=>"v4"}]
xm = Builder::XmlMarkup.new(:indent => 2)
xm.table {
  xm.tr { data[0].keys.each { |key| xm.th(key)}}
  data.each { |row| xm.tr { row.values.each { |value| xm.td(value)}}}
}
puts "#{xm}"

выход

<table>
  <tr>
    <th>col1</th>
    <th>col2</th>
  </tr>
  <tr>
    <td>v1</td>
    <td>v2</td>
  </tr>
  <tr>
    <td>v3</td>
    <td>v4</td>
  </tr>
</table>
4 голосов
/ 14 апреля 2010

Вы можете использовать builder:

require 'builder'

a = [{"col1"=>"v1", "col2"=>"v2"}, {"col1"=>"v3", "col2"=>"v4"}]
builder = Builder::XmlMarkup.new
columns = a.first.keys
builder.table do |t|
  t.tr do |tr|
    columns.each do |col|
      tr.th(col)
    end
  end
  a.each do |row|
    t.tr do |tr|
      columns.each do |col|
        tr.td(row[col])
      end
    end
  end
end
p builder.target
#=> "<table><tr><th>col1</th><th>col2</th></tr><tr><td>v1</td><td>v2</td></tr><tr><td>v3</td><td>v4</td></tr></table><target/>"
4 голосов
/ 14 апреля 2010

Это не кажется особенно трудным сделать вручную. В зависимости от того, где вы собираетесь его использовать, это, вероятно, должно где-то использоваться в своем собственном методе, но вот небольшой сценарий, который я только что написал:

table.rb

class Array 
  def to_cells(tag)
    self.map { |c| "<#{tag}>#{c}</#{tag}>" }.join
  end
end

rows = [{"col1"=>"v1", "col2"=>"v2"}, {"col1"=>"v3", "col2"=>"v4"}]
headers = "<tr>#{rows[0].keys.to_cells('th')}</tr>"
cells = rows.map do |row|
  "<tr>#{row.values.to_cells('td')}</tr>"
end.join("\n  ")
table = "<table>
  #{headers}
  #{cells}
</table>"
puts table

Выход:

<table>
  <tr><th>col1</th><th>col2</th></tr>
  <tr><td>v1</td><td>v2</td></tr>
  <tr><td>v3</td><td>v4</td></tr>
</table>

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

Причина, по которой нет драгоценного камня, заключается в том, что создание таблицы на самом деле не является огромным делом. Удивительно, что вы можете делать, когда вы сгибаетесь и сами что-то кодируете:)

1 голос
/ 15 августа 2012

Ответ Matchu очень вдохновил меня, и я изменил его на самоопределяемые методы вместо изменения встроенного класса (не делайте этого, если у вас нет действительно веской причины)

Кроме того, при создании таблицы структура массива может быть гораздо более удобной и интуитивно понятной для доступа к элементам.

Пусть вся таблица хранится в двумерном массиве, скажем

@table_array = [
                 ["Name","Gender","Age"],
                 ["Andy","M","20"],
                 ["Mary","F","19"],
                 ["Tony","M","18"]
              ]

, в котором каждый первый элемент служит заголовком таблицы, а остальные - содержимым таблицы. Теперь мы можем использовать хорошо отформатированный table_array и атрибут класса таблицы для генерации HTML-кода таблицы:

def ToCell (tag,value)
    value.map{ |c| "<#{tag}>#{c}</#{tag}>" }.join   
end

def ToTable (table_array, table_class)
    headers = "<tr>" + ToCell('th',table_array[0]) + "</tr>"
    cells = table_array[1..table_array.count].map{ |each_row|
        "<tr>#{ToCell('td',each_row)}</tr>"             
    }.join

    table = "<table class=\"#{table_class}\"><thead>#{headers}</thead><tbody>#{cells}</tbody></table>"
end

и вставьте его в файл .erb

<%= ToTable(@table_array,"table").html_safe %>

вывод будет примерно таким, если вы видите из браузера

<table class="table">
     <thead>
            <tr><th>Name</th><th>Gender</th><th>Age</th></tr>
     </thead>
     <tbody>
            <tr><td>Andy</td><td>M</td><td>20</td></tr>
            <tr><td>Mary</td><td>F</td><td>19</td></tr>
            <tr><td>Tony</td><td>M</td><td>18</td></tr>
     </tbody>
</table>
0 голосов
/ 05 мая 2016

Драгоценный камень dom , который я разработал, обладает функциональностью того, что вы хотите сделать. Вы можете легко создать такую ​​таблицу в коде Ruby:

require "dom"
[%w[aaa bbb], %w[ccc ddd]].dom(:td, :tr, :table)
# => "<table><tr><td>aaa</td><td>bbb</td></tr><tr><td>ccc</td><td>ddd</td></tr></table>"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...