Tool of Thought

APL for the Practical Man

"You don't know how bad your design is until you write about it."

Constructing HTML Tables

June 4, 2021

In my HTML project, I have been constructing HTML tables like so:

NewTable←{
     ⍝ ⍵ ←→ Namepace
     ⍝      ⍵.Titles (vec of char vecs)
     ⍝      ⍵.Values (Matrix of char vecs)
     ⍝      ⍵.Footer (v/v of footer values)
     ⍝      ⍵.Classes (vec of char vecs)
     ⍝ ← ←→ Table
     ⍺←0
     newRow←{⍺ New'tr'}
     newCell←{New'td'⍵}
     t←⍺ New'table'
     th←t New'thead'
     hr←th newRow 0
     hc←hr{⍺ New'th'⍵}¨⍵.Titles
     hc.class←⍵.Classes
     tb←t New'tbody'
     cd←newCell¨⍵.Values
     r←tb newRow¨⍳≢⍵.Values
     r.Content←↓cd
     r.Content.class←⊂⍵.Classes
     0=⍵.⎕NC'Footer':t
     0=≢⍵.Footer:t
     tf←t New'tfoot'
     fr←tf newRow 0
     fc←fr{⍺ New'th'⍵}¨⍵.Footer
     fc.class←⍵.Classes
     t
 }

I was not really happy about this, the primary reason being the definition of the argument; it seemed somewhat over specified for the general style of the project. When I had to inject additional class settings into particular rows and columns, I realized I had done it all wrong, and now have:

 NewTable←{
     ⍝ ⍺ ←→ [Parent Element]
     ⍝ ⍵ ←→ Rows, Columns, [Header Rows, [Footer Rows]]
     ⍝ ← ←→ Table
     ⍺←0
     nr nc nh nf←4↑⍵
     newHF←{
         n m←⍵
         n=0:⍬
         e←New ⍺
         r←n New'tr'
         e.Content←r
         r.Content←(n⍴m)New¨⊂'th'
         e
     }
     t←⍺ New'table'
     t.Content,←'thead'newHF nh nc
     tb←t New'tbody'
     r←nr New'tr'
     tb.Content←r
     r.Content←(nr⍴nc)New¨⊂'td'
     t.Content,←'tfoot'newHF nf nc
     t
 }

Now, the table is initially created with no data, just the properly structured DOM elements with no cell content, no attributes, no nothing:

      t←H.NewTable 2 3 1
      H.DOM2HTML t
<table>        
  <thead>      
    <tr>       
      <th></th>
      <th></th>
      <th></th>
    </tr>      
  </thead>     
  <tbody>      
    <tr>       
      <td></td>
      <td></td>
      <td></td>
    </tr>      
    <tr>       
      <td></td>
      <td></td>
      <td></td>
    </tr>      
  </tbody>     
</table>       

In addition I added a small set of functions for extracting table-specfic elements, for assigning content, setting attributes, etc.:

      b←H.BodyCells t
      b.Content←2 3⍴⍕¨⍳6
      h←,H.HeaderCells t 
      h.Content←'Column '∘,¨'One' 'Two' 'Three'
      c←H.Cells t
      c.class←(⍴c)⍴'left' 'right' 'right'
      H.DOM2HTML t
<table>                                  
  <thead>                                
    <tr>                                 
      <th class="left">Column One</th>   
      <th class="right">Column Two</th>  
      <th class="right">Column Three</th>
    </tr>                                
  </thead>                               
  <tbody>                                
    <tr>                                 
      <td class="left">0</td>            
      <td class="right">1</td>           
      <td class="right">2</td>           
    </tr>                                
    <tr>                                 
      <td class="left">3</td>            
      <td class="right">4</td>           
      <td class="right">5</td>           
    </tr>                                
  </tbody>                               
</table>        

Much better, much lighter, much more freedom for the APL programmer.