| Dieses Dokument befindet sich noch im Aufbau. Der Abschnitt über die DOM-Parser ist noch unvollständig. |
Grundlagen und Allgemeines
XML-Parser bieten über zwei verschiedene Schnittstellen Zugriff auf ein XML-Dokument: SAX
oder DOM
. SAX steht für "Simple API for XML
" und ist ereignisorientiert ("event based"). Das bedeutet, dass der Parser das XML-Dokument sequenziell einliest und bei einem bestimmten XML-Konstrukt ein Ereignis auslöst (z.B. bei einem aufgehenden oder schließenden XML-Tag, einem Attribut oder bei Text). Im Gegensatz dazu, wird bei DOM ("Document Object Model
") beim Parsen des XML-Dokuments ein Baum aufgebaut. Dieser sogenannte DOM-Tree ist das Abbild des XML-Dokuments und wird im Speicher vorgehalten.
Vor- und Nachteile zwischen SAX und DOM:
- SAX: schnell, minimaler Speicherverbrauch, Parsen direkt beim Einlesen des XML-Dokuments möglich, umständlich beim Parsen von komplexen XML-Dokumenten
- DOM: langsamer, hoher Speicherverbrauch, Zugriff erst nach kompletten Einlesen des XML-Dokuments möglich, einfacher Zugriff und Manipulation des XML-Dokuments über DOM-Tree
Alle hier aufgeführten Parser basieren auf der C-Bibliothek libxml2
, die Bestandteil des IPhone SDKs ist und sowohl SAX als auch DOM unterstützt.
SAX-Parser
Apple CFoundation Class "NSXMLParser"
Bestandteil des IPhone SDKs ist die Objective-C Klasse NSXMLParser
und implementiert mittels der C-Bibliothek libxml2 einen SAX-Parser. Der Parser durchläuft das XML-Dokument und ruft für bestimmte XML-Konstrukte verschiedene Methoden des delegierten Objekts auf. Im folgenden eine einfache Implementierung für das Parsen der Heise-Webseite
:
Folgender HTML-Code von der Heise Webseite ...
... erzeugt diese Debug-Ausgabe im Beispielprogramm:
2009-05-03 15:18:53.797 ParserTest[14281:20b] startElement: li 2009-05-03 15:18:53.798 ParserTest[14281:20b] startElement: a 2009-05-03 15:18:53.798 ParserTest[14281:20b] attrs: href = "http://www.heise.de/ct/Datenschuetzer-Das-Jahr-der-Skandale-nicht-der-Konsequenzen--/news/meldung/135491" 2009-05-03 15:18:53.799 ParserTest[14281:20b] attrs: title = "Datenschützer: "Das Jahr der Skandale, nicht der Konsequenzen"" 2009-05-03 15:18:53.799 ParserTest[14281:20b] chars: "Das Jahr der Skandale, nicht der Konsequenzen" 2009-05-03 15:18:53.799 ParserTest[14281:20b] endElement: a 2009-05-03 15:18:53.801 ParserTest[14281:20b] endElement: li
Das Parsen von wohlgeformten XHTML-Code, wie auf der Heise-Webseite, funktioniert mit dem NSXMLParser einwandfrei. Bei nicht-XML-konformen, "unsauberen" HTML-Code treten jedoch Probleme auf. Folgender HTML-Code ...
... erzeugt diese Debug-Ausgabe:
2009-05-03 14:57:19.259 ParserTest[14155:20b] startElement: TABLE 2009-05-03 14:57:19.260 ParserTest[14155:20b] attrs: CLASS = "infoBox" 2009-05-03 14:57:19.261 ParserTest[14155:20b] chars: 1 CELLSPACING=0 CELLPADDING=0> 2009-05-03 14:57:19.263 ParserTest[14155:20b] startElement: TR 2009-05-03 14:57:19.263 ParserTest[14155:20b] startElement: TD 2009-05-03 14:57:19.271 ParserTest[14155:20b] attrs: CLASS = "infoBox" 2009-05-03 14:57:19.271 ParserTest[14155:20b] chars: 2009-05-03 14:57:19.272 ParserTest[14155:20b] startElement: DIV 2009-05-03 14:57:19.272 ParserTest[14155:20b] attrs: CLASS = "infoBoxTitle" 2009-05-03 14:57:19.273 ParserTest[14155:20b] chars: Current Status 2009-05-03 14:57:19.274 ParserTest[14155:20b] endElement: DIV
HTML-Attribute werden irrtümlich als Text (cellspacing=0, cellpadding=0) oder gar nicht erkannt (border=1). Teilweise führt HTML-Code sogar zu Speicherzugriffsfehlern (Absturz IPhone Applikation).
Zusätzlich kommt es bei sehr großen XML-Dokumenten zu einem erhöhten Speicherverbrauch, da das komplette Dokument dem libxml-Parser übergeben wird. Besser wäre eine inkrementelle Übergabe von Teilen des XML-Dokuments. So könnte zusätzlich auch ein XML-Dokument schon beim Einlesen (z.B. während des Downloads von einem Server) geparst und die gesamte Bearbeitungszeit verkürzt werden. Als letzte Herausforderung ist der "case-sensitiv" Zugriff auf die XML-Attribute über die NSDictionary-Objekte zu erwähnen. Es gibt "von Haus aus" keine Möglichkeit unabhängig von der Groß- und Kleinschreibung der NSDictonary-Keys (also der Namen der XML-Attribute) auf die Werte zuzugreifen. Eine ausführliche Diskussion hierzu ist bei Apple-List
zu finden.
AQXMLParser
Die Objective-C Klasse AQXMLParser setzt auf den NSXMLParser auf und versucht die genannten Probleme zu lösen. Hierzu wird das XML-Dokument über ein NSInputStream-Objekt in 1kb großen Datenstücken an die libxml2-Methode "xmlParseChunk()" weitergereicht. Ein Vergleich zum Speicherverbrauch gegenüber NSXMLParser ist auf dem Blog des Entwicklers
zu finden. Der Quellcode des Parser
ist bei github veröffentlicht.
Zusätzlich bietet die Klasse einen HTML-Modus, mit dem auch nicht wohlgeformter HTML-Code einwandfrei geparst werden kann.
Der oben aufgeführte HTML-Code, der vom NSXMLParser nicht richtig geparst wurde, macht beim AQXMLParser im HTML-Modus kein Problem:
2009-05-03 16:12:38.536 ParserTest[17346:20b] startElement: table 2009-05-03 16:12:38.536 ParserTest[17346:20b] attrs: cellpadding = "0" 2009-05-03 16:12:38.536 ParserTest[17346:20b] attrs: class = "infoBox" 2009-05-03 16:12:38.537 ParserTest[17346:20b] attrs: border = "1" 2009-05-03 16:12:38.538 ParserTest[17346:20b] attrs: cellspacing = "0" 2009-05-03 16:12:38.538 ParserTest[17346:20b] chars: 2009-05-03 16:12:38.539 ParserTest[17346:20b] startElement: tr 2009-05-03 16:12:38.540 ParserTest[17346:20b] startElement: td 2009-05-03 16:12:38.540 ParserTest[17346:20b] attrs: class = "infoBox" 2009-05-03 16:12:38.541 ParserTest[17346:20b] chars: 2009-05-03 16:12:38.541 ParserTest[17346:20b] startElement: div 2009-05-03 16:12:38.541 ParserTest[17346:20b] attrs: class = "infoBoxTitle" 2009-05-03 16:12:38.542 ParserTest[17346:20b] chars: Current Network Status 2009-05-03 16:12:38.542 ParserTest[17346:20b] endElement: div
Jedoch bricht der XML-Parser sofort bei sämtlichen Parser-Fehlern den kompletten Prozess ab:
2009-05-03 16:12:39.259 ParserTest[17346:20b] startElement: td 2009-05-03 16:12:39.261 ParserTest[17346:20b] attrs: align = "left" 2009-05-03 16:12:39.264 ParserTest[17346:20b] attrs: valign = "center" 2009-05-03 16:12:39.264 ParserTest[17346:20b] attrs: class = "statusEven" 2009-05-03 16:12:39.265 ParserTest[17346:20b] ==> ERROR: Operation could not be completed. (NSXMLParserErrorDomain error 23.) -> (null) 2009-05-03 16:12:39.265 ParserTest[17346:20b] startElement: a
Außerdem kommt es beim Kompilieren des Quellcodes beim "@property parserError" in der Header-Datei AQXMLPaser.h zu Syntax-Fehlern und beim Einlesen von NSData über die Methode "initWithData" zu Speicherzugriffsfehler. Folgender Patch behebt die Fehler und ergänzt eine neue Boolean-Variable abortOnErrors mit Setter- (setAbortOnErrors()) und Getter-Methode (abortOnErrors()), über die konfiguriert wird, ob bei XML Parser-Fehler das Parsen abgebrochen werden soll:
Aufruf der Klasse für das Parsen von HTML-Code:
Software:Patch
für AQXMLParser:
XML-Parser-Beispiel "XMLPerformance" von Apple
Apple stellt auf der Developer-Seite eine Beispiel-Implementierung eines performanten XML-Parsers als Alternative zu NSXMLParser zur Verfügung:
DOM-Parser
Übersicht der DOM-Parser für das IPhone mit einigen Notizen:
- XPathQuery: http://cocoawithlove.com/2008/10/using-libxml2-for-parsing-and-xpath.html
- parsen von nicht wohlgeformten HTML möglich
- baut DOM-Tree mit Objective-C Objekten auf
- einfacher Zugriff auf Elemente und Attribute des XML-Dokuments
- bei großen Dokumenten sehr lange Parse-Zeiten und hoher Speicherverbrauch: bei 800kb HTML 10MB Speicher und 15 Sekunden Parse-Zeit
- Hpple: http://github.com/topfunky/hpple/tree/master
- setzt auf XPathQuery auf und vereinfacht den Zugriff noch weiter (weitere Abstraktion)
- parst das Dokument bei XPath-Suchen jedes Mal erneut
- kein intuitiver Zugriff auf Child-Knoten
- TouchXML: http://code.google.com/p/touchcode/wiki/TouchXML
- eigene Implementierung von NSXMLDocument
- hauptsächlich zum Lesen von XML-Dokumenten (später auch Modifizierung)
- Element-Parser: http://touchtank.wordpress.com/element-parser/
- parsen von nicht wohlgeformten HTML möglich
- für kommerziellen Einsatz wird 100$ Lizenz pro Produkt fällig
SAX-/DOM-Parser
Kombination aus SAX und DOM-Parser in einer Objective-C Klasse:
- Objective-XML: http://www.metaobject.com/blog/
