Tim Jansen's Blog (deutsch)


2003/09/26
KDE 4.0
Schon seit längerer Zeit nervt mich die Komplexität von XML Parser APIs. Modelle wie DOM wurden erstellt für dokumenten-artige, relativ frei geformte Sprachen wie HTML und DocBook. Aber wenn man sie zum Lesen starrer XML Dokumente wie SOAP Nachrichten benutzt, schreibt man Unmengen von Code für die trivialsten Dinge. Die Krönung des Schwachsinns ist SAX. SAX führt nur bei recht wenigen Anwendungen zu kompaktem, erträglichem Code. Ein Pull-Parser ist SAX in wohl jedem Aspekt überlegen. Der verbreiteste Pull-Parser derzeit ist .Net's XmlReader, den ich auch vergleichweise nett finde. Das Hauptproblem beim Lesen starrer Dokumente aber bleibt: es gibt keine einfache Möglichkeit um Zahlen, Daten und andere Werte zu bekommen und dabei das Format zu überprüfen. Als ich Sonntag irgendwo den Begriff XML Serialisierung gelesen habe, fiel mir die Lösung ein: man überträgt einfach das gute, alte C++ Serialisierungprinzip (wie in QDataStream) auf XML. Das geht zwar nicht 1:1, weil mehr Meta-Daten gebraucht werden, aber es kommt zumindest halbwegs nahe und ist besser als alle anderen Parser. (Der Begriff "XML Serialisierung" wird von Microsoft für ihren Pull-Parser und eine entsprechende Klasse zum Schreiben von XML benutzt, hat aber mit den besonderen Features dieser API nichts weiter zu tun)
Ein Beispiel für ein relativ einfaches XML Dokument ist folgendes:

<x:person xmlns:x="urn:kde:person">
<x:name order="firstlast">Joe Public</x:name>
<x:size>185</x:size>
<y:email xmlns:y="urn:kde:email-extension">joe@kde.org</y:email>
</x:person>

Dieses zu Parsen mit DOM ist die Hölle. Mit meiner API wird es etwa so aussehen:

XmlReader r(/* Initialize with InputStream or DOM tree */);
QString name, nameOrder, email;
int size;
r >> TNamespace("urn:kde:person")
>> TOpenElement("person")
>> TReadElement("name", name)
>> TReadAttribute("order", nameOrder)
>> TReadElement("size", size)
>> TNamespace("urn:kde:email-extension")
>> TReadElement("email", email)
>> TNamespace("urn:kde:person")
>> TCloseElement();
if (r.error())
// do something...


Das macht XML Parsen erträglich. Ich habe auch noch ein paar Lösungen für optionale oder sich wiederholende Elemente, und für andere Anwendungsfälle soll XmlReader auch noch eine 'traditionelle' Zugriffsfunktionen bekommen. Passend dazu gibt es einen XmlWriter, mit dem XML Dateien mit demselben Prinzip geschrieben werden können. Ich werde wohl noch das Wochenende und vieleicht dar¨ber hinaus damit beschäftigt sein, diese API zu schreiben, was meine Knot Pläne weiter verzögert. Aber ich brauche die API einfach....

XML
Beim Schreiben besagter API ist mir aufgefallen, wie sehr XML nervt. Das Problem sind dabei gar nicht die üblichen Punkte, wie etwa die "Attribut oder Element"-Frage, "Mixed-Content" und ähnliche Kritikpunkte. Das Problem sind die SGML-Altlasten, die in XML übernommen wurden und die Spezifikation verseuchen, obwohl sie einfach nur unnötig sind bzw durch XML Schema und ähnliche Mechanismen ersetzt wurden. Damit meine ich DTDs, 'Processing Instructions', 'Internal Entities' und 'CData'. Die meisten Leute kennen diese wahrscheinlich nicht einmal und kümmern sich nicht weiter darum. Wenn man aber eine API wie DOM sauber benutzen will, muss man es. Beispielsweise gibt es drei Nodes, die Text enthalten können (Text, EntityReference und CData), was gerade einfache Aufgaben, wie den Text eines Elementes zu lesen, unglaublich erschwert. Zumindest, wenn man sich nicht für sowas seine eigenen Helferklassen schreibt. XmlReader wird standardmössig diesen Kram ignorieren - es sei denn, man aktiviert es explizit.



This page is powered by Blogger. Isn't yours? Creative Commons License
All text in this blog is licensed under a Creative Commons License.
(Images containing screenshots etc are excluded)