2010-04-13 37 views
8

Cách tốt nhất (lý tưởng là đá quý, nhưng đoạn mã nếu cần) để tạo bảng HTML từ một mảng băm?Tạo bảng HTML từ mảng băm trong Ruby

Ví dụ, mảng này băm:

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

nên tạo ra bảng này:

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

Trả lời

9

Sử dụng XMLBuilder cho việc này:

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

Output

<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

này dường như không đặc biệt khó khăn để làm bằng tay. Tùy thuộc vào nơi bạn sẽ sử dụng nó, điều này có lẽ nên đi trong phương pháp riêng của mình ở đâu đó, nhưng đây là kịch bản ít tôi chỉ viết lên:

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 

Output :

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

Rõ ràng, có một số vấn đề - cho một, nó giả định rằng hàng tiêu đề của một người cũng giống như tất cả các nhóm khác. Bạn có thể xử lý trước và làm việc xung quanh điều này khá dễ dàng, tuy nhiên, bằng cách điền vào nils trong tất cả các hàng cho tất cả các tiêu đề không được chỉ định đúng.

Lý do không có đá quý là tạo bảng không thực sự là một cam kết lớn. Thật ngạc nhiên là những gì bạn có thể làm khi bạn khóa xuống và thực sự đang điều gì đó cho mình :)

+0

Tôi nhận thấy rằng, vì tôi đã thay đổi kịch bản, đầu ra chắc chắn không phải vậy. Chỉnh sửa chỉ trong một giây. – Matchu

+1

Đã chỉnh sửa. Tốt hơn nhiều. – Matchu

4

Bạn có thể sử dụng 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/>" 
+0

Đó là chúng tôi đăng cùng một giải pháp cùng một lúc :-) –

1

Trả lời của Matchu r đã truyền cảm hứng cho tôi rất nhiều và tôi đã sửa đổi nó thành các phương thức tự định nghĩa thay vì thay đổi lớp dựng sẵn (đừng làm điều này trừ khi bạn có một lý do thực sự tốt).

Ngoài việc tạo bảng, cấu trúc của Array có thể thuận tiện hơn và trực quan hơn để truy cập các phần tử.

Hãy để cho toàn bộ bảng được lưu trữ trong một mảng 2-D, nói

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

trong đó mỗi phần tử đầu tiên đóng vai trò tiêu đề bảng và phần còn lại là nội dung bảng. Bây giờ chúng tôi có thể sử dụng bảng định dạng được định dạng tốt và thuộc tính lớp bảng để tạo mã html bảng:

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 

và nhúng vào.ERB nộp

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

đầu ra sẽ là một cái gì đó như thế này nếu u nhìn thấy từ trình duyệt

<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> 
10
# 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 
+2

Câu trả lời này bị đánh giá quá thấp. –

+0

đã xếp hạng địa điểm này :) – zee

+0

cảm ơn các bạn! :) – Tilo

0

Các dom ngọc mà tôi đã phát triển có chức năng về những gì bạn muốn làm. Bạn có thể tạo một bảng như thế này một cách dễ dàng trong mã 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>" 
Các vấn đề liên quan