Bayes 0.4.2
Nicht wundern, wenn die Tage ein Update für das Spamblock-Bayes-Plugin hereinkommt und erstmal keine Änderungen auffallen. Es sind keine großen dabei.
Es wurde: Ein kleiner Bug gefixt, der auftrat, wenn anfangs die Optionen nicht gespeichert wurden, eine deutsche Dokumentation hinzugefügt, Beschreibungstexte ganz leicht angepasst und ein paar CSS und Html-Änderungen im erweiterten Menü eingebaut.
HTML reparieren mit JTidy
Vermutlich kommt sxp mit ungültigem XML oder seltsamen HTML besser zurecht als die meisten XML-Parser. Manchmal sind die Fehler aber zu gravierend, oder man will Fehlerquellen minimieren. Dann ist JTidy praktisch: Der Fork von HTML Tidy behebt HTML-Fehler schlichtweg und liefert sauberen Code zurück. Wenn man mit Seiten aus der echten Welt arbeitet statt mit vermutlich sauberen API-Ausgaben ist sowas einfach notwendig.
Zwei Beispiele von der "HTML Tidy"-Seite:
<a href="#refs">References<a>
<a href="#refs">References</a>
<h1><i>italic heading</h1> <p>new paragraph
<h1><i>italic heading</i></h1> <p>new paragraph
Ich weiß nicht mehr, welche Seite und welche Codestelle so zerschossen war, dass ich es initial gebraucht habe. Ich weiß noch, dass es bei den Arbeiten am Blogzähler war und das jTidy das Problem löste. Seitdem lasse ich es einfach standardmäßig über die Seiten laufen.
HTML-Boxen gleicher Größe: boxHeight
Das heute vorgestellte Projekt ist eine Nummer kleiner. BoxHeight ist ein kleines Stück Javascript, dem man ids von Elementen gibt, die daraufhin auf die gleiche Größe (die größte) gesetzt werden. Das ist praktisch wenn man divs hat, die nebeneinander sind und, unabhängig von der Länge des enthaltenen Textes, gleich groß sein sollen.
Ohne Angleichung |
Mit boxHeight |
Natürlich gibt es dafür auch jQuery-Plugins, doch da das noch nicht genutzt wurde wollte ich es nicht für eine solche Kleinigkeit (und da man den Code auch selbst schreiben könnte) einbinden.
Xpath für XML als String unter Java - StringyXmlReader
Der StringyXmlParser ist von mir. Er versteht XML als String, iteriert dort drüber, um schließlich einen String oder einen Vektor von Strings zurückzugeben.
Bevor ich das weiter erkläre sollte ich die Vorgeschichte erzählen, bevor mir hierfür später mal der Kopf abgerissen wird. Eine Api gab XML zurück und das musst geparst werden. Also schaute ich mir an, was es dafür unter Java so alles gibt. Zuerst fand ich SAX, und auch wenn das inzwischen alles seinen Sinn hat: Die impliziten Funktionsaufrufen bei den Events habe ich damals schlichtweg nicht verstanden.
Dann versuchte ich, ein DOM-Objekt zu erstellen, und bekam dort immer null zurück, in ähnliche Fehler rannte ich noch bei anderen Wegen. Schießlich wurde mir das zu blöd, die Auflistung der vorhandenen Tools ist doch eine Aufzählung des Elends. Ich suchte noch eine Weile und habe dabei wahrscheinlich eine äußerst einfache Lösung übersehen (nicht vergessen: Ich rannte in Bugs oder machte etwas falsch, sodass solche netten Lösungen nicht funktionierten). Schließlich beschloss ich, mir eben selbst den Komfort zu bauen den es unter Bash schon lange gibt: Ein Tool, das XML als String und einen XPath-Ausdruck frisst und daraufhin einen Wert zurückgibt.
getNode(xml, xpath)
Also zum StringyXmlParser. Die grundsätzliche Benutzung sollte aus folgendem Beispiel klarwerden:
String xml = "<root>" + "<group>" + "<field>" + "abc" + "</field>" + "<field>" + "def" + "</field>" + "</group>" + "</root>"; StringyXmlParser sxp = new StringyXmlParser(); Vector<String> nodes = sxp.getNode(xml, "/root/group"); for (String node: nodes) { assertTrue(node.equals("<group><field>abc</field><field>def</field></group>")); }
getValue(xml)
Will man nicht einen kompletten Node, sondern den Inhalt eines Nodes:
String xml = "<root id=\"1\" value=\"abc def\" data=\"12dv\" >" + "<group>" + "<field>" + "abc" + "</field>" + "</group>" + "</root>"; StringyXmlParser sxp = new StringyXmlParser(); String value = sxp.getValue(sxp.getNode(xml, "/root/group/field").get(0)); assertTrue(value.equals("abc"));
getAttribute(xml, id)
Ebenso einfach kommt man an Attribute:
String xml = "<root id=\"1\" value=\"abc def\" data=\"12dv\" >" + "<group>" + "<field />" + "</group>" + "</root>"; StringyXmlParser sxp = new StringyXmlParser(); String attribute1 = sxp.getAttribute(xml, "id"); String attribute2 = sxp.getAttribute(xml, "value"); assertTrue(attribute1.equals("1")); assertTrue(attribute2.equals("abc def"));
searchNode(xml, nodeName)
Natürlich gibt es auch die Möglichkeit, einfach nach einem Node zu suchen:
String xml = "<root>" + "<group>" + "<field>" + "abc" + "</field>" + "<field>" + "def" + "</field>" + "</group>" + "</root>"; StringyXmlParser sxp = new StringyXmlParser(); Vector<String> nodes = sxp.searchNode(xml, "group"); for (String node: nodes) { assertTrue(node.equals("<group><field>abc</field><field>def</field></group>")); }
searchComplex(xml, nodeName1, value, nodeName2, rückgabetyp, exakteGleichheit)
Oder auch komplizierter: In der Gruppe, bei der ein Node (field1) einen bestimmten Wert hat (abc), wird der Wert des benachbarten Nodes (field2) zurückgegeben (oder der ganze Node, wenn rückgabeytp false ist). Das brauchte ich oft:
String xml = "<root>" + "<group>" + "<field1>" + "abc" + "</field1>" + "<field2>" + "def" + "</field2>" + "</group>" + "</root>"; StringyXmlParser sxp = new StringyXmlParser(); String value = sxp.searchComplex(xml, "field1", "abc", "field2", true, false).get(0); assertTrue(value.equals("def"));
Abschlussworte
Ist das nun die Erleuchtung, der definitive Weg um mit XML-Dateien umzugehen? Eher nicht. Ich benutze den Parser, um sowohl HTML als auch XML auszulesen, z.B. nutzt der Blogzähler ihn um auf den Blogs nach Faktoren für eine bestimme Blogplattform zu suchen. Das funktioniert ziemlich gut, also: Dort funktioniert sxp ziemlich gut. Doch wenn man in den Code schaut wird man feststellen, dass er keineswegs garantiert funktionieren wird - er betrachtet XML eben als String und geht dementsprechend dort durch. Das kann scheitern (stringy bedeutet nicht umsonst auch zäh). Dagegen finde ich es aber äußerst interessant und vermisste das früher oft, dass sxp einen Node einfach wieder als XML frisst und man darauf direkt wieder einen Xpath-Ausdruck anwenden kann. Das ist der Vorteil, wenn man syntaktische Korrektheit schlichtweg ignoriert.
An sich ist die Benutzung des StringyXmlParsers ein angenehmer und sehr einfacher Weg, mit XML umzugehen. Ich bin recht sicher, dass ich ihn noch eine Weile als eines meiner Standardwerkzeuge unter Java benutzen werde, solange ich nicht in unheilbare Bugs oder gravierende Performance-Probleme renne (die sich bisher nicht abzeichneten). Nebenbei: Lizenz ist die GPL.
Download: StringyXmlParser-0.1.tar.gz
DB4O
Db4o ist eine freie Datenbank für Objekte. In meiner Datenbankvorlesung habe ich noch gelernt, dass sowas zwar faszinierend, aber esoterischer Quatsch ist, der in der Praxis aus diversen Gründen nicht funktioniert. Es mag auch durchaus sein, dass es Gründe gibt, db4o nicht einzusetzen - bei meinem (natürlich vergleichsweise kleinem) Projekt konnte ich keine finden.
Speichern
Nochmal: db4o ist eine Datenbank für Objekte. Man speichert ein Objekt hinein und bekommt zu einem beliebigen späteren Zeitpunkt genau das gleiche Objekt zurück. Das Speichern ist simpel:
Cpu cpu = new Cpu(); ObjectContainer cpuDB = Db4o.openFile("cpus");; cpuDB.store(cpu);
Hier wurde eine Datei als Datenbank verwendet, "cpus", und dort hinein das neuerstelle Objekt gespeichert.
Select
Aber Speichern hilft nicht, wenn es nicht einfache Wege gibt, wieder das Objekt zu holen. db4o kennt zwei, und der erste ist wirklich simpel: queryByExample. Man erstellt ein Objekt, bei dem das Suchattribut gesetzt ist, alles andere steht auf default und wird ignoriert. Dann übergibt man das der Datenbank und bekommt all die Objekte mit dem gleichen Attribut zurück. Ein Beispiel:
Cpu exampleCpu = new Cpu(); exampleCpu.setSocket("A"); ObjectContainer cpuDB = Db4o.openFile("cpus"); ObjectSet<Cpu> cpuResult = cpuDB.queryByExample(exampleCpu); // ==>Nur Cpus mit Sockel A
Und ein Select *, also alle Cpus? Das geht über die Klasse:
ObjectSet<Cpu> cpuResult = cpuDB.queryByExample(Cpu.class);
Alternativ gibt es noch die native queries. Bei ihnen läuft ein Matcher über die Datenbank:
// Nur Cpus günstiger als 200: List<Cpu> result = container.query(new Predicate<Cpu>() { public boolean match(Cpu cpu) { return cpu.price < 200; } });
Editieren
Eine Objektdatenbank, oder zumindest db4o, hat eine andere Definition von Identität als eine SQL-Datenbank. Es wird nicht einfach ein unique key auf id gesetzt und dann verhindert die Datenbank, dass so etwas nochmal eingesetzt wird, und wird bei db4o ein Objekt gespeichert, das die gleichen Attribute wie ein anderes hat, ist ein solches Objekt eben zweimal vorhanden. Trotzdem kann man ein Objekt holen, editieren und mit den Änderungen speichern, ohne dass es Duplikate gibt:
private void updatePrice(Cpu cpu, double price, ObjectContainer cpuDB) { ObjectSet<Cpu> found = cpuDB.queryByExample(cpu); cpu = found.get(0); cpu.price = price; cpuDB.store(cpu); }
Löschen folgt dem gleichen Prinzip:
public void delete(Cpu cpu) { ObjectContainer cpuDB = Db4o.openFile(path+"cpus"); ObjectSet found = cpuDB.queryByExample(cpu); cpuDB.delete(found.get(0)); cpuDB.close(); }
Fazit
Db4o hat mich ziemlich begeistert. Ich musste einige Objekte speichern und wieder holen, und mir war klar, dass sich die Struktur dieser Objekte im Laufe der Entwicklung noch häufig ändern wird. Jedesmal ein SQL-Schema abzuändern oder neu zu erstellen wäre grausam gewesen. Überhaupt ein SQL-Schema zu erstellen wäre grausam gewesen. So brauchte ich mich darum nicht kümmern: Objekt gespeichert, Objekt geholt. Änderte sich mal was an den Objekten, wurde die alte Datenbank eben gelöscht, erstellt sich ja von selbst neu.
Ich kann die Performance nicht bewerten - es ist möglich, dass db4o bei großen Datenmengen gegen eine SQL-Datenbank verliert. Ich kann nicht sagen, ob es ansonsten gewichtige Gründe gibt, diese Objektdatenbank zu meiden, ich spare mir hier das Aufzählen der theoretischen Gegenargumente. Aber ich kann sagen: Bei mir hat db4o wunderbar funktioniert und die Entwicklung erheblich vereinfacht. Wenn ich nochmal Daten speichern will, die als Objekt bereits vorliegen und so wieder gebraucht werden, würde ich es nochmal hiermit versuchen.
Projektvorstellungen
Im Laufe der Woche will ich ein oder zwei Projekte vorstellen - nicht unbedingt welche von mir, sondern solche Helfer, über die ich bei der Erstellung eines eigenen Programms, einer Webanwendung, gestolpert bin. An diesem Projekt sitze ich seit etwa einem halben Jahr, natürlich nicht durchgängig, und an diesem Wochenende konnte ich mit Freude feststellen: "Ich bin fertig oO".
Wenn alles gut geht kann ich also letztendlich auch das vorstellen, wobei ich mir noch nicht sicher bin, ob es nicht doch noch länger als eine Woche braucht um das online zu stellen.
Denken und Fliegen
Eines der neun von Turing vorweggenommenen Argumente gegen die Möglichkeit einer starken KI bezieht sich auf Ada Lovelaces Zitat:
It has no pretensions to originate anything. It can do whatever we know how to order it to perform.
Bei uns in der Diskussion darüber fiel der folgende Satz:
Ein Flugzeug kann auch besser fliegen als sein Ingenieur.
Fand ich treffend.
MSDN AA
Das Microsoft-Programm, über das Studenten kostenlos an Lizenzen für Micoroft-Produkte wie Windows kommen, zeigt, wie kompliziert soetwas zu bewerten ist - und wie einfach, Microsoft komplett feindlich gegenüberzustehen.
Lernen schon Studenten primär mit Software von Microsoft zu arbeiten, werden sie auch in Zukunft damit arbeiten. Würden sie gezwungen sein, freie Alternativen zu testen, wäre das auch später für sie eine Option.
Die Fesselung an eine beherrschende amerikanische Firma ist potentiell ungesund. Aber diese Feststellung baut auf einigen Prämissen auf. So benötigt sie z.B. die Überzeugung, dass Software in gewissem Maße Auswirkungen auf die Gesellschaft hat. Da ist man sich wahrscheinlich recht schnell einig. Daraus wiederum kommt man schnell zum Schluss, dass folglich Software frei sein muss - denn nur, wenn das was die Gesellschaft mitkontrolliert von der Gesellschaft kontrollierbar ist, wird sie nicht unweigerlich von außen gesteuert.
Beispiel: Computer stünden in jeder Wohnung. Um erfolgreich an der Schule/Uni mitarbeiten zu können, braucht es Zugriff auf das Internet. Auch der sei kostenlos, von der Regierung gestellt. Wenn nun Windows das einzige Betriebssystem wäre und Windows teuer, eben nicht kostenlos jedem Bedürftigen zur Verfügung gestellt, würde schon deshalb der Erfolg in der Schule/Uni vom Geldbeutel bestimmt.
Um solche Szenarien zu verhindern braucht es freie Software. Um freie Software zu fördern müsste gerade die "Elite", eben die Studierenden, lernen damit umzugehen und die Prinzipien dahinter wertzuschätzen. Ein Programm wie MSDN AA wäre demnach hochgradig schädlich, wenn die Uni das in ihr Lehren einbaut und die Veranstaltungen Windows voraussetzen.
Man kann das auch anders sehen. Durch Gesetze kann eine Gesellschaft ja auch Kontrolle über Software ausüben - oder man verneint die Wichtigkeit von freier Software für freie Bildung und für alle anderen Beispiele, in denen sie als Alternative dient. Dann kann man sich auf den Standpunkt stellen, dass es wichtiger sei, dass Studenten lernen was in der Wirtschaft benutzt wird. Je nach dem um welches Studienfach es dann geht und was der konkrete Berufswunsch ist kann es dann gut sein, dass dies eine Software von Microsoft ist - oder andere proprietäre Software, man übertrage die Argumentation auf Designer und Photoshop. Und was bringen idealistische Studenten mit Kenntnissen im Bereich freier Software, wenn der Arbeitgeber von der Geisteswissenschaftlerin Excel-Spezialkenntnisse und vom Programmierer als Grundvoraussetzung die perfekte Beherrschung von Visual Studio will? Dann wäre die kostenlose Möglichkeit, diese Software kennenzulernen, hilfreich. (Anstoßgeber)