2010-03-14 4 views
7

이전에 파이썬을 사용하여 코딩 한 테이블 (작업 일정)을 만들려고합니다. Clojure 언어에 대한 훌륭한 소개가 될 것입니다.중첩 된 맵 (및 벡터)에서 HTML 테이블 만들기

나는 Clojure (또는 그 문제에있어서의 Lisp)에 대한 경험이 거의 없으며 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에 이동이 원래에 대한 를 사용하여 단계별로 시도하고 있었다 마지막 DOM을 (더 성공적으로 보인다) 및 html 테이블 (내 원래 파이썬 프로그램은 sqlite 데이터베이스에서 COM을 사용하여 Excel 스프레드 시트에 출력)에 내용을 덤핑. 내가 '처럼

섹션 (급여, 관리자 등)와 섹션의 이름으로 테이블을 출력
(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)) 

, 난 그냥 느낌 : 여기

내 시도 (만들기 테이블을 FN)입니다 너무 많은 시간을 중첩 시켜서 domap을 악용하는 것은 아마 적절한 열에서 근무 시간을 얻기 위해 더 많은 돔을 추가해야 할 것이고 코드는 그것에 '더러운'느낌을 갖게됩니다.

충분한 정보가 포함되어 있지 않은 경우 사전에 사과드립니다. 코딩에 대한 도움을 요청하지 않으며, 제 1의 질문입니다. :)

이 작업을 수행하는 데 더 나은 방법을 알고 있거나 초보자로서 알아야 할 팁이나 트릭을 알고 있다면 분명히 환영받을 것입니다.

감사합니다.

+0

향후 커뮤니티 위키와 같이 답을 묻는 질문을 표시해서는 안됩니다. 이것은 우리의 평판 수집 게임을 망쳐 놓습니다. ;-) –

+0

죄송합니다, 나는 그것이 rep 시스템을 버렸음을 깨닫지 못했습니다. 나는 그저 내 질문이 편집 가능하다는 것을 의미한다고 생각했다. (어쨌든있을 필요는 없다.) (그러나 관계없이 응답 해 주셔서 감사합니다.) 귀하의 게시물에서 많은 것을 배웠습니다. :) – Kenny164

+0

듣기를 기쁘게 생각합니다. :-) –

답변

3

중첩 루프의 어떤 종류를 방지 할 수있는 방법은 없습니다. 그러나 당신은 domap을 전혀 필요로하지 않습니다. Compojure는 당신을 위해 seq를 확장하기에는 (때로는) 똑똑합니다. listmapfor이면 충분합니다. 예를 미할 Marczyk의 대답은, 또는 경우 :

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

"는 서열를 통해지도와 같은 태그에 모든 것을 포장"패턴은 충분히 내가 때때로을위한 도우미 기능을 사용하고자하는 것이 일반적이다.

Compojure는 한 레벨을 seq 확장합니다. 따라서 list에 몇 가지 물건을 던져 HTML 출력에 태그가 순차적으로 표시되도록 할 수 있습니다. 그러면 h1과 hr이 표시됩니다. 코드에서 h1과 hr을 버리는 것입니다.

그러나 한 레벨 만 확장됩니다. 목록 목록이나 seq 목록이있을 때 외부 seq는 확장되지만 내부 seq는 확장되지 않습니다.

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

내부 seq가 Compojure barf를 만드는 방법을 참조하십시오. 어떻게 작동하는지보고 싶다면 compojure.html.gen/expand-seqs을 보거나 돌보면 변경/수정하십시오. for 게으른 서열을 반환 이후

, 당신은 for 또는 listfor을 중첩 된 문제가 될 수 있습니다. 그러나 seq-in-a-seq를 피하는 것이 좋습니다. 위의 list*을 사용합니다. listhtml의 조합도 작동합니다. 다른 많은 방법이 있습니다.

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

와우 감사합니다.지도 태그 도우미 기능 아이디어가 정말 마음에 듭니다. 그리고 당신은 저에게 연구 목록 *을 만들었습니다. – Kenny164

2

코드에 약간의 문제가 있다고 생각합니다. 아래 코드에서 문제를 바로 잡으려고했습니다. 이것을 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)) 
+0

흠, div의 사용이 실제로 마음에 들었습니다. 중첩 루프를 포함하는 좋은 방법입니다. (너무 많은 인수가있는 것에 대해 불만을 나타 냈습니다. 감사합니다. – Kenny164

+0

아쉽게도 Brian의 글은 create table에서'html',': hr',': table'을'html' 형식으로 싸지 못했음을 깨닫게했습니다. .. 잠시 후에 고칠 것입니다. ': div'에 관해서는, 나는 괜찮 았다고 생각했고 실제로는 가장 명확한 코드로 만들었지 만, 당신이 원칙적으로 할 수있는 concat's /'list * '등으로 그것 없이는 할 수 있습니다. –

+0

div 행의 표 행이나 셀을 배치하는 것이 HTML 표준에서 허용되지 않는다고 생각합니다. 나는 틀릴 수 있었다. –

관련 문제