2010-03-14 7 views
7

Estoy tratando de crear una tabla (un programa de trabajo) He codificado previamente el uso de Python, creo que sería una buena introducción al lenguaje Clojure para mí.Crear una tabla HTML a partir de mapas anidados (y vectores)

Tengo muy poca experiencia en Clojure (o lisp en ese asunto) y he hecho mis rondas en google y un poco de prueba y error, pero parece que no puedo entender este estilo de codificación.

Aquí es mis datos de la muestra (vendrán de una base de datos SQLite en el futuro):

(def smpl2 (ref {"Salaried" 
      [{"John Doe" ["12:00-20:00" nil nil nil "11:00-19:00"]} 
       {"Mary Jane" [nil "12:00-20:00" nil nil nil "11:00-19:00"]}] 
      "Shift Manager" 
      [{"Peter Simpson" ["12:00-20:00" nil nil nil "11:00-19:00"]} 
       {"Joe Jones" [nil "12:00-20:00" nil nil nil "11:00-19:00"]}] 
      "Other" 
      [{"Super Man" ["07:00-16:00" "07:00-16:00" "07:00-16:00" 
         "07:00-16:00" "07:00-16:00"]}]})) 

yo estaba tratando de pasar por esta originalmente usando para luego pasar a doseq y finalmente domap (que parece tener más éxito) y volcar los contenidos en una tabla html (mi programa original de python superó este de una base de datos sqlite en una hoja de cálculo de Excel usando COM).

Aquí está mi intento (fn crear tabla):

(defn html-doc [title & body] 
    (html (doctype "xhtml/transitional") 
    [:html [:head [:title title]] [:body body]])) 

(defn create-table [] 
    [:h1 "Schedule"] 
    [:hr] 
    [:table (:style "border: 0; width: 90%") 
    [:th "Name"][:th "Mon"][:th "Tue"][:th "Wed"] 
    [:th "Thur"][:th "Fri"][:th "Sat"][:th "Sun"] 
    [:tr 
    (domap [ct @smpl2] 
     [:tr [:td (key ct)] 
     (domap [cl (val ct)] 
      (domap [c cl] 
       [:tr [:td (key c)]]))]) 
    ]]) 

(defroutes tstr 
    (GET "/" ((html-doc "Sample" create-table))) 
    (ANY "*" 404)) 

que da salida a la mesa con los apartados (a sueldo, gerente, etc.) y los nombres de las secciones, me siento como yo' Estoy abusando del domap al anidarlo demasiadas veces ya que probablemente necesite agregar más domaps solo para obtener los tiempos de cambio en sus columnas correctas y el código se está volviendo "sucio".

Pido disculpas de antemano si no incluyo suficiente información, normalmente no pido ayuda con la codificación, también esta es mi primera pregunta AS).

Si conoces algún método mejor para hacer esto o incluso consejos o trucos que debería conocer como novato, definitivamente son bienvenidos.

Gracias.

+0

Para el futuro, no debe marcar preguntas que responden como esta comunidad wiki. Esto arruina nuestro juego de recopilación de reputación. ;-) –

+0

Lo siento, no me di cuenta de que arrojó el sistema de rep. Solo pensé que significaba que mi pregunta era editable (que no tenía que ser de todos modos) :(. Pero gracias por responder independientemente, he aprendido bastante de tus publicaciones :) :) – Kenny164

+0

Feliz de escuchar eso. :-) –

Respuesta

3

No hay manera de evitar algún tipo de bucle anidado. Pero no necesita domap en absoluto, Compojure es lo suficientemente inteligente (a veces) para expandir un seq por usted. list y map y for son suficientes. Por ejemplo, la respuesta de Michał Marczyk, o:

(defn map-tag [tag xs] 
    (map (fn [x] [tag x]) xs)) 

(defn create-table [] 
    (list 
    [:h1 "Schedule"] 
    [:hr] 
    [:table {:style "border: 0; width: 90%"} 
    [:tr (map-tag :th ["Name" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat" "Sun"])] 
    [:tr (for [[category people] smpl2] 
      (list* [:tr [:td category]] 
        (for [person people 
         [name hours] person] 
        [:tr [:td name] (map-tag :td hours)])))]])) 

El "mapa sobre una ss y envolver todo en la misma etiqueta de" patrón es suficiente que me gusta usar una función de ayuda para los que a veces común.

Compojure amplía un nivel de seq para usted. Así que puedes incluir algunas cosas en un list para que las etiquetas aparezcan secuencialmente en tu salida de HTML, lo cual hice para que aparecieran h1 y hr. En tu código, solo estás lanzando h1 y hr.

Pero tenga en cuenta que solo se expande un nivel. Cuando tiene una lista de listas, o una lista de seqs, el seq externo se expandirá pero los internos no.

user> (println (html (list [:div "foo"] (for [x [1 2 3]] [:div x])))) 
<div>foo</div>[email protected] 

Vea cómo el seq interno hace Compojure barf. Consulte compojure.html.gen/expand-seqs para ver cómo funciona esto o cámbielo/fíjelo si lo desea.

Esto puede ser un problema cuando se han anidado o una forfor en un list, ya que devuelve un for siguientes perezoso. Pero solo debes evitar tener un seq-in-a-seq. Yo uso list* arriba. Una combinación de list y html también funcionaría. Hay muchas otras formas.

user> (println (html (list* [:div "foo"] (for [x [1 2 3]] [:div x])))) 
<div>foo</div><div>1</div><div>2</div><div>3</div> 

user> (println (html (list [:div "foo"] (html (for [x [1 2 3]] [:div x]))))) 
<div>foo</div><div>1</div><div>2</div><div>3</div> 
+0

Wow gracias, me gusta mucho la idea de función de ayuda de etiqueta de mapa, y me has hecho una lista de búsqueda * (que tampoco sabía que existía) – Kenny164

2

Creo que tienes algunos problemas menores con tu código. Intenté corregirlos en el siguiente código. Probando esto con Compojure 0.3.2, me atrevo a decir que funciona. (No dude en señalar todo lo que requiere la mejora o parece no funcionar para usted, por supuesto.)

(use 'compojure) ; you'd use a ns form normally 

;;; I'm not using a ref here; this doesn't change much, 
;;; though with a ref/atom/whatever you'd have to take care 
;;; to dereference it once per request so as to generate a consistent 
;;; (though possibly outdated, of course) view of data; 
;;; this doesn't come into play here anyway 
(def smpl2 {"Salaried"  [{"John Doe" ["12:00-20:00" nil nil nil "11:00-19:00"]} 
          {"Mary Jane" [nil "12:00-20:00" nil nil nil "11:00-19:00"]}] 
      "Shift Manager" [{"Peter Simpson" ["12:00-20:00" nil nil nil "11:00-19:00"]} 
          {"Joe Jones" [nil "12:00-20:00" nil nil nil "11:00-19:00"]}] 
      "Other"   [{"Super Man" ["07:00-16:00" "07:00-16:00" "07:00-16:00" 
              "07:00-16:00" "07:00-16:00"]}]}) 

(defn html-doc [title & body] 
    (html (doctype :xhtml-transitional) ; the idiomatic way to insert 
             ; the xtml/transitional doctype 
     [:html 
     [:head [:title title]] 
     [:body body]])) 

(defn create-table [] 
    (html 
    [:h1 "Schedule"] 
    [:hr] 
    [:table {:style "border: 0; width: 90%;"} 
    [:tr 
    [:th "Name"][:th "Mon"][:th "Tue"][:th "Wed"] 
    [:th "Thur"][:th "Fri"][:th "Sat"][:th "Sun"]] 
    (for [category smpl2] 
     [:div [:tr [:td (key category)]] ; for returns just one thing per 
             ; 'iteration', so I'm using a div 
             ; to package two things together; 
             ; it could be avoided, so tell me 
             ; if it's a problem 
     (for [people (val category)] 
     (for [person people] 
      [:tr 
      [:td (key person)] 
      (for [hours (val person)] 
       [:td hours])]))])])) 

(defn index-html [request] 
    (html-doc "Sample" (create-table))) 

(defroutes test-routes 
    (GET "/" index-html) 
    (ANY "*" 404)) 

(defserver test-server 
    {:port 8080} 
    "/*" 
    (servlet test-routes)) 
+0

hmm, me gustó el uso del div en realidad, es una buena manera de contener los bucles anidados (esa es la razón principal por la que me mudé en el 1er lugar, por quejé de tener demasiados argumentos). Gracias – Kenny164

+0

Ouch, la publicación de Brian me hizo darme cuenta de que no pude ajustar ': h1',': hr' y ': table' en una forma' html' en create-table, así que también los he descartado. .. Se arreglará en un segundo. En cuanto al ': div', pensé que también estaba bien y en realidad estaba hecho para el código más claro, aunque con algunos' concat's/'list *' s etc. en principio podrías prescindir de él. –

+0

Creo que envolver las filas o celdas de la tabla en divs no está permitido por el estándar HTML. Sin embargo, podría estar equivocado. –

Cuestiones relacionadas