从Ruby中的哈希数组生成HTML表

时间:2010-04-13 23:59:03

标签: ruby-on-rails ruby html-table

从哈希数组中生成HTML表格的最佳方法(理想情况是gem,但必要时还有代码片段)是什么?

例如,这个哈希数组:

[{"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 个答案:

答案 0 :(得分:12)

# 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

答案 1 :(得分:10)

使用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>

答案 2 :(得分:4)

这似乎并不特别难以手工完成。根据你将要使用它的位置,这可能应该在某个地方使用自己的方法,但是这里是我刚刚编写的小脚本:

<强> 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,以便所有标题都没有正确分配。

没有宝石的原因是生成表并不是一项巨大的任务。当你扣下并自己编写代码时,你可以做些什么:)

答案 3 :(得分:4)

您可以使用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 :(得分:1)

Matchu的答案给了我很多启发,我将其修改为自定义方法,而不是更改内置类(除非你有一个非常好的理由,否则不要这样做)。

此外,在生成表时,Array的结构可能更方便,更直观地访问元素。

让整个表存储在二维数组中,比如说

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

答案 5 :(得分:0)

我开发的dom gem具有您想要做的功能。您可以在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>"