Bisher habe ich auf wikihost.org das diff-Tool der Linux-Shell verwendet, um den Anwendern eines Wikis die Möglichkeit zu geben, zwei unterschiedliche Versionen einer Wiki-Seite hinsichtlich ihrer Unterschiede zu vergleichen. Dabei wurden einfach die beiden Wiki-Sources temporär als Datei weggeschrieben, das externe diff aufgerufen und der Output wieder eingelesen und interpretiert.
Dieser Ansatz hatte einige Nachteile, wie z.B. das Unvermögen mit Unicode-Zeichen umzugehen, die Verarbeitungsgeschwindigkeit und eine unschöne Darstellung.
Aus genannten Gründen war ich daher auf der Suche nach einer vernünftigen, integrierten Lösung. Gefunden habe ich eine sehr schöne für mehrere Sprachen entwickelte Bibliothek.
Google Diff, Match and Patch
Die diff, match and patch-Bibliothek von Neil Fraser stellt identische Funktionen für Java, JavaScript, Dart, C++, C#, Objective C, Lua und Python bereit. Sie wird auf code.google.com gehostet und unter der Apache License 2.0 bereitgestellt.
Für wikihost.org ist die Java-Bibliothek relevant, daher beziehe ich mich hier ausschließlich darauf. Wikihost.org ist in Grails/Groovy entwickelt, daher zeige ich auch kurz, wie die Java-Bibliothek dort einzubinden ist.
Bibliothek ins Grails-Projekt aufnehmen
Damit die Java-Klassen der diff-Bibliothek in der Grails-Anwendung genutzt werden können, muss das Java-File einfach in das Verzeichnis <PROJECT>/src/java kopiert werden.
Hier die Projekt-Struktur des wikihost.org Grails-Projekts mit eingebundener diff-Bibliothek:

Ist das erledigt, kann man auch schon beginnen, die diff-Funktionalität in einem der Controller zu nutzen.
Diff in Grails ermitteln
Hier der Code, wie ich ihn zum Vergleich der Revisionen einer Wiki-Seite nutze:
//Initialisiere diff-Bibliothek
def dmp = new diffy.diff_match_patch()
//Vergleiche alte und neue Version
def diffed = dmp.diff_main(oldRevText,newRevText)
//mache für Menschen lesbar (optimierte Darstellung)
dmp.diff_cleanupSemantic(diffed)
//als HTML ausgeben (färbe gelöschte Teile rot, Hinzugefügte grün)
def TextHtml = dmp.diff_prettyHtml(diffed)
Zuerst wird eine Instanz der Klasse diff_match_patch initiiert. Den Package-Namen diffy habe ich in der Klasse definiert, damit ich leichter erkenne, wo diese Klasse herkommt. Der eigentliche Vergleich zwischen oldRevText und newRevText findet dann in der zweiten Zeile durch Aufruf der Methode diff_main() statt. Da die Differenz zwischen den beiden Versionen durch Veränderungsschritte (was muss gelöscht und hinzugefügt werden, um vom alten auf den neuen Zustand zu kommen aka Levenshtein-Distanz) dargestellt werden, wäre in vielen Fällen ein kaum entzifferbares Ergebnis, wie in diesem Beispiel der Fall:

Durch den Aufruf der Methode diff_cleanupSemantic() wird dies lesbarer gemacht, indem die einzelnen diffs zu größeren Blöcken zusammengefasst werden. Hier der selbe Vergleich mit nachträglicher Optimierung:

Mit der Methode diff_prettyHtml() kann eine simple HTML-Ausgabe erzeugt werden. Möchte man das Ergebnis nicht für eine HTML-Seite
Das Ergebnis liegt zum Schluss in der Variable TextHtml und wird an die GSP-Seite zur Ausgabe im Browser durchgereicht.
Selbst ausprobieren kann man die Funktionen der Bibliothek unter http://neil.fraser.name/software/diff_match_patch/svn/trunk/demos/demo_diff.html direkt im Browser.
