Создайте HTML-таблицу из вложенных карт (и векторы)

Я пытаюсь составить таблицу (график работ), я кодировал ранее Python использования, я думаю, что это было бы хорошее введение в язык Clojure для меня.

У меня есть очень мало опыта в Clojure (или шепелявость в том вопросе), и я сделал мои раунды в Google и хорошем бите метода проб и ошибок, но, может казаться, не получаю голову вокруг этого стиля кодирования.

Вот мои демонстрационные данные (будет прибывать из sqlite базы данных в будущем):

(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"]}]}))

Я пытался ступить через это первоначально использующее для того, чтобы затем перейти на doseq и наконец domap (который кажется более успешным), и дамп содержания в таблицу HTML (моя исходная программа Python произвела это от sqlite базы данных в электронную таблицу Excel с помощью COM).

Вот моя попытка (создавать-таблица fn):

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

Это производит таблицу с разделами (оплачиваемый, менеджер, и т.д.) и имена в разделах, я просто чувствую, что злоупотребляю domap вложением она слишком много раз, поскольку я должен буду, вероятно, добавить больше domaps только для получения времен сдвига в их надлежащих столбцах, и код получает 'грязное' ощущение к ней.

Я приношу извинения заранее, если я не включаю достаточно информации, я обычно не обращаюсь за помощью на кодировании, также это - мое 1-е ТАК вопрос :).

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

Спасибо.

8
задан 2 revs 14 March 2010 в 23:15
поделиться

2 ответа

Нет никакого способа избежать вложенного цикла. Но вам совсем не нужен domap, Compojure достаточно умен (иногда), чтобы расширить seq за вас. Достаточно list и map и for. Например, ответ Михала Марчика, или:

(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)])))]]))

Шаблон "map over a seq и обернуть все в один тег" встречается достаточно часто, чтобы я иногда использовал для него вспомогательную функцию.

Compojure расширяет один уровень seq для вас. Таким образом, вы можете бросить некоторые вещи в list, чтобы теги появлялись последовательно в вашем HTML-выводе, что я и сделал, чтобы h1 и hr появились. В вашем коде вы просто отбрасываете h1 и hr.

Но обратите внимание, что это расширяет только один уровень. Когда у вас есть список списков или список секвенций, внешняя секвенция будет расширяться, а внутренние - нет.

user> (println (html (list [:div "foo"] (for [x [1 2 3]] [:div x]))))
<div>foo</div>clojure.lang.LazySeq@ea73bbfd

Посмотрите, как внутренний seq вызывает у Compojure рвоту. Посмотрите в compojure.html.gen/expand-seqs, чтобы увидеть, как это работает, или измените/исправьте это, если хотите.

Это может быть проблемой, когда у вас есть вложенные for или for в list, поскольку for возвращает ленивый seq. Но нужно просто избегать seq-in-a-seq. Я использую list* выше. Комбинация list и html тоже подойдет. Есть много других способов.

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>
4
ответ дан 5 December 2019 в 21:17
поделиться

Я думаю, что у вас есть несколько небольших проблем с кодом. Я попытался исправить их в приведенном ниже коде. Тестируя это с Compojure 0.3.2, я осмелюсь сказать, что это работает. (Не стесняйтесь, конечно, указывать на то, что требует улучшения или не работает для вас)

(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))
3
ответ дан 5 December 2019 в 21:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: