Einträge bezüglich Monat gruppieren
02.05.2005
Es ist oftmals üblich, eine Liste von Einträge anzuzeigen, welche nach dem Datum sortiert ist. Weil diese Liste recht lang werden kann, ist es vernünftig, die Liste zu gruppieren und jede Gruppe mit einer Kopfzeile zu markieren. Wenn Sie die Gruppierung bezüglich eines Datums herstellen wollen, können Sie das MTDateHeader Tag verwenden. Aber was kann man machen, wenn man bezüglich des Monats gruppieren will?
Ein Beispiel
Angenommen in Ihrem Weblog gibt es eine Reihe von Einträgen. Diese wollen Sie wie folgt strukturieren:
16. Januar 2005
- Erster Eintrag vom 16. Januar 2005
- Zweiter Eintrag vom 16. Januar 2005
- Dritter Eintrag vom 16. Januar 2005
20. Januar 2005
- Erster Eintrag vom 20. Januar 2005
- Zweiter Eintrag vom 20. Januar 2005
3. Februar 2005
- Erster Eintrag vom 3. Februar 2005
- Zweiter Eintrag vom 3. Februar 2005
6. Februar 2005
- Erster Eintrag vom 6. Februar 2005
Wir können eine derartige Liste einfach mit den MTDateHeader und MTDateFooter Tags erstellen. Dafür könnten wir zum Beispiel die folgenden Zeilen verwenden.
<MTEntries>
<MTDateHeader>
<p><$MTEntryDate format="%B %e, Y"$></p>
<ul>
</MTDateHeader>
<li><$MTEntryTitle$></li>
<MTDateFooter>
</ul>
</MTDateFooter>
</MTEntries>
Das MTDateHeader Tag ist ein so genanntes Container Tag. Movable Type wird seinen Inhalt nur genau dann auswerten, wenn der aktuelle Eintrag der erste Eintrag zu einem Datum ist. Im obigen Beispiel nutzen wir dieses Tag, um das Datum auszugeben und die Liste zu beginnen. Auf gleiche Weise wird das MTDateFooter Tag verwendet, um die Liste abzuschließen.
Stellen wir uns nun einmal vor, dass wir eine Liste ähnlich der obigen erzeugen wollen. Der Unterschied soll aber sein, dass diese bezüglich des Monats der Veröffentlichung gruppiert ist. Die Liste soll wie folgt aussehen.
Januar 2005
- Erster Eintrag vom 16. Januar 2005
- Zweiter Eintrag vom 16. Januar 2005
- Dritter Eintrag vom 16. Januar 2005
- Erster Eintrag vom 20. Januar 2005
- Zweiter Eintrag vom 20. Januar 2005
Februar 2005
- Erster Eintrag vom 3. Februar 2005
- Zweiter Eintrag vom 3. Februar 2005
- Erster Eintrag vom 6. Februar 2005
Das MTDateHeader Tag besitzt kein Argument, um ein "prüfe den Monat der Veröffentlichung um herauszufinden, ob eine neue Gruppe anfangen muss" umzusetzen. Deshalb können wir es hier nicht verwenden.
Eventuell gibt es ein spezielles Plugin, welches genau diese Funktionalität anbietet. Wir werden aber in der Lage sein, die Liste selbst zu erstellen. Das hat sogar einige Vorteile.
- Wir werden unterschiedliche Bedingungen für den Gruppenwechsel realisieren können. Zum Beispiel könnte es sein, dass wir dann eine neue Gruppe anfangen wollen, wenn sich der erste Buchstabe des Titels ändert.
- Die Movable Type Umgebung hängt nicht von zu vielen spezialisierten Plugins ab.
- Es macht viel mehr Spaß, es selbst zu entwickeln.
Dann wollen wir es einmal versuchen, die Funktionalität mit möglichst wenig Unterstützung durch spezialisierte Plugins zu realisieren.
Voraussetzungen
Wir benötigen zwei allgemeine Plugins. Das eine ist das Compare Plugin, welches ich im Artikel in Vergleiche für bedingte Generierungen beschrieben habe. Das andere Plugin ist das TagInvoke Plugin, welches ich in dem Artikel Ein Tag in einem Tag vorgestellt habe.
Ich betrachte beide Plugins als "allgemein verwendbar". Sie können in einer Vielzahl von Situationen verwendet werden und sollten eigentlich mit jedem Movable Type installiert werden. Ich kann beide Plugins empfehlen.
Falls Sie dies noch nicht getan haben, lesen Sie bitte die beiden Artikel und installieren Sie die Plugins.
Programmierung einer gruppierten Liste
Eine gruppierte Liste zu programmieren, ist eigentlich keine komplizierte Angelegenheit. Es ist ein normales Szenario bei einer Software Entwicklung. In Pseudocode kann die grundlegende Struktur wie folgt skizziert werden.
prev_group = ""
this_group = ""
For Each elem In list
this_group = calc_group_from_element(elem)
If this_group <> prev_group Then
Print this_group
prev_group = this_group
End If
Print elem
Next
Wir benötigen zwei Variablen - eine für den aktuellen Gruppennamen (this_group) und eine für den vorherigen Gruppennamen (prev_group). Der Hauptteil des Programms ist dann eine Schleife, welche über alle Einträge hinwegläuft.
Für jeden Eintrag wird dessen Gruppe berechnet (hier durch einen einfachen Funktionsaufruf abgekürzt). Anschließend wird der Name der aktuellen Gruppe mit dem der vorherigen Gruppe verglichen. Wenn beide identisch sind, befinden wir uns immer noch in derselben Gruppe - nichts muss getan werden. Wenn die Namen aber unterschiedlich sind, haben wir gerade eben eine neue Gruppe betreten. Dann muss die entsprechende Kopfzeile ausgegeben und die Variable für die aktuelle Gruppe geändert werden. Abschließend kann dann der eigentliche Eintrag ausgegeben werden.
Damit das Ganze auch funktioniert, muss die Liste nach dem Gruppenfeld sortiert sein. Wenn wir nach dem Monat gruppieren wollen, muss die Liste nach dem Veröffentlichungsdatum sortiert sein. Wenn wir nach dem ersten Buchstaben des Titels gruppieren wollen, muss sie nach dem Titel sortiert sein.
Umstellung auf die Tag-Sprache
Die Tag-Sprache von Movable Type ist nicht gerade die erste Wahl, wenn es darum geht, Programmlogik auszudrücken. Aber viele Möglichkeiten sind versteckt. Man kann viel mehr mit den Tags erreichen, als man anfangs denkt. Versuchen wir es einfach einmal.
Die zwei Zuweisungen am Anfang sind trivial, weil Movable Type ein spezielles Tag für die Zuweisung anbietet.
prev_group = ""
this_group = ""
<MTSetVar name="mgs_prev_group" value="">
<MTSetVar name="mgs_this_group" value="">
Sogar die Schleife über alle Einträge ist einfach. Es gibt das MTEntries Tag, welches mit Hilfe von Argumenten beeinflusst werden kann. Um eine Liste aller Einträge, welche nach dem Datum aufsteigend sortiert ist, zu erzeugen, können wir folgendes benutzen.
For Each elem In list
...
Next
<MTEntries sort_order="ascend">
...
</MTEntries>
Nun müssen wir das erste kleine Problem bewältigen. Die Zuweisung des aktuellen Gruppennamens an eine Variable ist nicht ganz trivial. Wir könnten denken, dass folgendes doch eigentlich die Lösung sein sollte.
this_group = calc_group_from_element(elem)
<MTSetVar name="mgs_this_group"
value="<MTEntryDate format="%Y-%m">">
Wie ich aber in dem Artikel Ein Tag in einem Tag beschrieben habe, wird dies nicht funktionieren. Movable Type wertet nämlich ein Tag innerhalb eines anderen Tags nicht aus. Wir müssen das MTTagInvoke Plugin für diese Aufgabe einsetzen.
this_group = calc_group_from_element(elem)
<MTTagInvoke tag_name="MTSetVar" name="mgs_this_group">
<MTTagAttribute name="value"><MTEntryDate
format="%Y-%m"></MTTagAttribute>
</MTTagInvoke>
Nach diesen Zeilen wird die Variable »mgs_this_group« den aktuellen Gruppennamen enthalten. Der Wert wird vom Muster YYYY-MM sein, wobei YYYY das vierstellige Jahr und MM der zweistellige Monat ist. Wenn beispielsweise der aktuelle Eintrag vom "3. Februar 2005" ist, wird die Variable den Text "2005-03" enthalten.
Nun müssen wir uns um den Vergleich kümmern. Auch hier ist Movable Type nicht direkt in der Lage, einen derartigen Ausdruck zu unterstützen. Wir werden dafür das Compare Plugin verwenden. Schauen Sie sich am besten den Artikel Vergleiche für bedingte Generierungen an, wenn Sie mit diesem Plugin nicht vertraut sind.
If this_group <> prev_group Then
...
End If
<MTIfNotEqual a="[MTGetVar name='mgs_this_group']"
b="[MTGetVar name='mgs_prev_group']">
...
</MTIfNotEqual>
Die Ausgabe des des aktuellen Gruppennamens ist einfach.
Print this_group
<p><b><MTGetVar name="mgs_this_group"></b></p>
Die Zuweisung des aktuellen Gruppennamens an die Variable für den vorherigen Gruppennamen ist ein Szenario, wo uns wiederum das MTTagInvoke Plugin hilft.
prev_group = this_group
<MTTagInvoke tag_name="MTSetVar" name="mgs_prev_group">
<MTTagAttribute name="value"><MTGetVar
name="mgs_this_group"></MTTagAttribute>
</MTTagInvoke>
Nun muss nur noch eine einzige Anweisung umgesetzt werden. Diese ist einfach.
Print elem
<p><MTEntryTitle></p>
Wenn wir nun alle Teile zusammenfügen, erhalten wir das endgültige Ergebnis. Es ist wie folgt.
<MTSetVar name="mgs_prev_group" value="">
<MTSetVar name="mgs_this_group" value="">
<MTEntries sort_order="ascend">
<MTTagInvoke tag_name="MTSetVar" name="mgs_this_group">
<MTTagAttribute name="value">
<MTEntryDate format="%Y-%m">
</MTTagAttribute>
</MTTagInvoke>
<MTIfNotEqual a="[MTGetVar name='mgs_this_group']"
b="[MTGetVar name='mgs_prev_group']">
<p><b><MTGetVar name="mgs_this_group"></b></p>
<MTTagInvoke tag_name="MTSetVar" name="mgs_prev_group">
<MTTagAttribute name="value"><MTGetVar
name="mgs_this_group"></MTTagAttribute>
</MTTagInvoke>
</MTIfNotEqual>
<p><MTEntryTitle></p>
</MTEntries>
Wenn Sie die obigen Zeilen in eine Vorlagedatei kopieren, wird das Ergebnis wie erwartet sein. Eine Liste von Artikeln wird ausgegeben. Jeder Monat startet mit einem Gruppenkopf, in welchem der Monat angezeugt wird.
Erweiterungen
Natürlich sind die obigen Zielen vereinfachter Code, welcher nur die Struktur aufzeigen soll. Es ist aber einfach, ihn zu erweitern. Einige denkbare Erweiterungen sind...
- Momentan geben wir nur den Titel eines Artikels aus. Eventuell soll auch die Zusammenfassung erscheinen.
- Der Text des Gruppennamens wird aus dem 4-stelligen Jahr und dem 2-stelligen Monat aufgebaut. Wir könnten auch den Namen des Monats ausgeben, so dass zum Beispiel "Februar 2005" an Stelle von "2005-02" gedruckt wird.
- Das MTEntries Tag könnte erweitert werden, so dass eine gefilterte Liste von Einträgen gedruckt wird.
mgs | 02.05.2005
Feedback erwünscht!
Wie fanden Sie den Eintrag? Interessant? Langweilig? Ich freue mich über Ihren Kommentar. Wenn Ihnen der Eintrag geholfen hat, setzen Sie doch einen Link auf http://www.movable-type-weblog.de/.
Bitte keinen Spam
Um das Weblog vor Spam zu schützen, wird das MT-Approval Plugin eingesetzt. Sie müssen einen neuen Kommentar zunächst in der Vorschau ansehen, bevor dieser auf dem Server gespeichert werden kann. Ferner wird ein Kommentar erst gesichtet, bevor er freigegeben wird. Näheres finden Sie in meinem Artikel Weblog Spamming Grundlagen, wo einige Schutzmaßnahmen skizziert werden.
Wenn Sie sich an TypeKey angemeldet haben, wird Ihr Kommentar automatisch freigegeben.
Neuen Kommentar schreiben
TypeKey wurde an dieser Stelle vorübergehend deaktiviert. Erstellen Sie Ihren Kommentar bitte ohne TypeKey oder melden Sie sich im Vorschau-Dialog an.
Kommentar
Marvin_II | 16.05.05 19:57
Excellent, genau nach dieser Funktion hatte ich gesucht. Der Artikel hat mir sicherlich zwei oder drei Stunden hartes Nachdenken und diverse Versuche erspart. Gut und verständlich geschrieben. Das Beispiel konnte ich ohne Probleme übertragen und anpassen.
Danke
Marvin_II

