2010-03-14 6 views
7

Ich versuche, eine Tabelle (ein Arbeitsplan) zu erstellen Ich habe zuvor mit Python codiert, ich denke, es wäre eine nette Einführung in die Clojure-Sprache für mich.Erstellen Sie eine HTML-Tabelle aus verschachtelten Karten (und Vektoren)

Ich habe sehr wenig Erfahrung in Clojure (oder lisp in dieser Angelegenheit) und ich habe meine Runden in Google und ein gutes Stück von Versuch und Irrtum, aber kann nicht scheinen, meinen Kopf um diese Art der Codierung zu bekommen.

Hier ist mein Beispieldaten (wird aus einer SQLite-Datenbank in der Zukunft kommen):

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

ich versuchte, durch diese ursprünglich mit dem Schritt für dann auf doseq bewegen und schließlich domap (was erfolgreicher scheint) und den Inhalt in eine HTML-Tabelle (meine ursprüngliche Python-Programm outputed dies aus einer SQLite-Datenbank in eine Excel-Tabelle mit COM).

Hier ist mein Versuch (der create-Tabelle 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)) 

, die die Tabelle mit den Abschnitten gibt (Angestellte, Manager, etc.) und die Namen in den Abschnitten, ich fühle mich wie ich Ich missbrauche die Domap, indem ich sie zu oft verschachtele, da ich wahrscheinlich mehr DOMAPs hinzufügen muss, nur um die Verschiebungszeiten in ihren richtigen Spalten zu erhalten, und der Code bekommt ein "schmutziges" Gefühl.

Ich entschuldige mich im Voraus, wenn ich nicht genug Informationen einschließe, bitte ich normalerweise nicht um Hilfe beim Codieren, auch das ist meine erste SO Frage :).

Wenn Sie irgendwelche besseren Ansätze kennen, um dies zu tun oder sogar Tipps oder Tricks, die ich als Neuling wissen sollte, sind sie auf jeden Fall willkommen.

Danke.

+0

Für die Zukunft sollten Sie keine beantwortbaren Fragen wie dieses Community-Wiki markieren. Dies verdirbt unser Reputationsspiel. ;-) –

+0

Sorry, mir ist nicht klar, dass es das Rep-System weggeworfen hat. Ich dachte nur, dass meine Frage bearbeitbar war (was sie sowieso nicht sein musste) :(. Aber danke, dass du trotzdem geantwortet hast, ich habe eine Menge von deinen Posts gelernt. :) – Kenny164

+0

Freut mich zu hören. :-) –

Antwort

3

Es gibt keine Möglichkeit, eine Art von verschachtelter Schleife zu vermeiden. Aber Sie brauchen domap überhaupt nicht, Compojure ist schlau genug (manchmal), um eine Seq für Sie zu erweitern. list und map und for sind genug. Zum Beispiel Michał Marczyk Antwort oder:

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

Das „a ff Karte über und alles im gleichen Tag wickelt“ Muster ist häufig genug, dass Ich mag manchmal eine Hilfsfunktion für sie verwenden.

Compojure erweitert eine Ebene von seq für Sie. So können Sie einige Sachen in eine list werfen, um zu erhalten, dass Tags in Ihrer HTML-Ausgabe der Reihe nach erscheinen, die ich tat, um die h1 und hr zu bekommen, um zu erscheinen. In Ihrem Code werfen Sie nur die h1 und hr weg.

Aber beachten Sie, dass es nur eine Ebene erweitert. Wenn Sie eine Liste von Listen oder eine Liste von Seqs haben, wird der äußere Seq erweitert, aber die inneren seq nicht.

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

Sehen Sie, wie die innere seq Compojure barf macht. Schauen Sie in compojure.html.gen/expand-seqs, um zu sehen, wie das funktioniert, oder ändern/reparieren Sie es, wenn Sie möchten.

Dies kann ein Problem sein, wenn Sie for oder eine for in einem list verschachtelt haben, da for einen faulen f zurück. Aber Sie müssen nur vermeiden, eine seq-in-a-seq zu haben. Ich benutze list* oben. Eine Kombination von list und html würde auch funktionieren. Es gibt viele andere Möglichkeiten.

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, danke, ich mag die Idee der Map-Tag-Hilfsfunktion, und Sie haben mich zur Forschungsliste gemacht * (von der ich auch keine Ahnung hatte) – Kenny164

2

Ich denke, Sie haben ein paar kleinere Probleme mit Ihrem Code. Ich habe versucht, sie im folgenden Code zu korrigieren. Testen Sie dies mit Compojure 0.3.2, ich wage zu sagen, dass es funktioniert. (Fühlen Sie sich frei, etwas weisen darauf hin, dass eine Verbesserung erfordert oder scheint nicht für Sie zu arbeiten, natürlich.)

(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, mochte die Verwendung der div tatsächlich, es ist eine nette Möglichkeit, die verschachtelten Schleifen (das ist der Hauptgrund, warum ich auf der ersten Stelle, für beschwert über zu viele Argumente) verschoben. Danke – Kenny164

+0

Autsch, Brians Posting ließ mich erkennen, dass ich die '' h1', ': hr' und': table' nicht in ein 'html' Formular in create-table geschrieben habe, also habe ich sie auch weggeworfen. .. Wird in einer Sekunde behoben. Was das ': div' anbetrifft, dachte ich, dass es auch in Ordnung ist und tatsächlich für den klarsten Code gemacht wurde, obwohl man mit einigen' concat's/'list *' s usw. prinzipiell darauf verzichten könnte. –

+0

Ich denke, Wrapping-Tabellenzeilen oder Zellen in Divs ist nicht vom HTML-Standard erlaubt. Ich könnte mich allerdings irren. –

Verwandte Themen