Java-Tipp 128: Erstellen Sie einen schnellen und schmutzigen XML-Parser

XML ist aus mehreren Gründen ein beliebtes Datenformat: Es ist für Menschen lesbar, selbstbeschreibend und portabel. Leider sind viele Java-basierte XML-Parser sehr groß. Beispielsweise haben Sun Microsystems jaxp.jarund parser.jarBibliotheken jeweils 1,4 MB. Wenn Sie mit begrenztem Speicher arbeiten (z. B. in einer J2ME-Umgebung (Java 2 Platform, Micro Edition)) oder die Bandbreite knapp ist (z. B. in einem Applet), ist die Verwendung dieser großen Parser möglicherweise keine praktikable Lösung .

Die Größe dieser Bibliotheken ist teilweise auf viele Funktionen zurückzuführen - möglicherweise mehr als Sie benötigen. Sie validieren XML-DTDs (Dokumenttypdefinitionen), möglicherweise Schemata und mehr. Möglicherweise wissen Sie jedoch bereits, dass Ihre Anwendung gültiges XML erhält. Möglicherweise möchten Sie bereits entscheiden, dass Sie nur den UTF-8-Zeichensatz verwenden möchten. Daher möchten Sie wirklich eine ereignisbasierte Verarbeitung von XML-Elementen und eine Übersetzung von Standard-XML-Entitäten - Sie möchten einen nicht validierenden Parser.

Hinweis: Sie können den Quellcode dieses Artikels unter Ressourcen herunterladen.

Warum nicht einfach SAX verwenden?

Sie können SAX-Schnittstellen (Simple API for XML) mit eingeschränkter Funktionalität implementieren und eine Ausnahme auslösen, die benannt wird, NotImplementedwenn Sie auf etwas Unnötiges stoßen.

Zweifellos könnten Sie etwas entwickeln, das viel kleiner ist als die 1,4-MB- jaxp.jar/parser.jarBibliotheken. Stattdessen können Sie die Codegröße noch weiter reduzieren, indem Sie Ihre eigenen Klassen definieren. Tatsächlich ist das Paket, das wir hier erstellen, erheblich kleiner als die JAR-Datei, die die SAX-Schnittstellendefinitionen enthält.

Unser schneller und schmutziger Parser ist ereignisbasiert wie der SAX-Parser. Ebenso wie der SAX-Parser können Sie eine Schnittstelle zum Abfangen und Verarbeiten von Ereignissen implementieren, die Attributen und Start- / Endelement-Tags entsprechen. Hoffentlich kennen diejenigen unter Ihnen, die SAX verwendet haben, diesen Parser.

Beschränken Sie die XML-Funktionalität

Viele Menschen möchten das einfache, selbstbeschreibende Textdatenformat von XML. Sie möchten auf einfache Weise Elemente, Attribute und deren Werte sowie den Textinhalt der Elemente auswählen. Lassen Sie uns vor diesem Hintergrund überlegen, welche Funktionen wir beibehalten müssen.

Unser einfaches Parsing-Paket hat nur eine Klasse QDParserund eine Schnittstelle DocHandler. Das QDParserselbst hat eine öffentliche statische Methode, parse(DocHandler,Reader)die wir als endliche Zustandsmaschine implementieren werden.

Unser Parser mit eingeschränkter Funktionalität behandelt die DTD- und Verarbeitungsanweisungen einfach als Kommentare, sodass sie nicht durch ihre Anwesenheit oder Verwendung ihres Inhalts verwechselt werden.

Da wir nicht verarbeiten DOCTYPE, kann unser Parser keine benutzerdefinierten Entitätsdefinitionen lesen. Es stehen nur die Standarddateien zur Verfügung: &, <,>, 'und ". Wenn dies ein Problem darstellt, können Sie Code einfügen, um benutzerdefinierte Definitionen zu erweitern, wie der Quellcode zeigt. Alternativ können Sie das Dokument vorverarbeiten - ersetzen benutzerdefinierte Entitätsdefinitionen mit ihrem erweiterten Text, bevor das Dokument an die übergeben wird QDParser.

Unser Parser kann auch keine bedingten Abschnitte unterstützen. zum Beispiel oder . Ohne die Möglichkeit, benutzerdefinierte Entitätsdefinitionen in zu definieren DOCTYPE, benötigen wir diese Funktionalität ohnehin nicht wirklich. Wir könnten solche Abschnitte gegebenenfalls verarbeiten, bevor die Daten an unsere Anwendung mit begrenztem Speicherplatz gesendet werden.

Da wir keine Attributdeklarationen verarbeiten, erfordert die XML-Spezifikation, dass alle Attributtypen berücksichtigt werden CDATA. Daher können wir einfach java.util.Hashtableanstelle der org.xml.sax.AttributeListAttributliste eines Elements verwenden. Wir haben nur Name / Wert-Informationen, die Hashtablewir verwenden können , aber wir brauchen keine getType()Methode, da sie CDATAsowieso immer zurückkehren würde.

Das Fehlen von Attributdeklarationen hat auch andere Konsequenzen. Beispielsweise liefert der Parser keine Standardattributwerte. Darüber hinaus können wir Leerzeichen mithilfe einer NMTOKENSDeklaration nicht automatisch reduzieren . Wir könnten jedoch beide Probleme bei der Vorbereitung unseres XML-Dokuments behandeln, sodass die zusätzliche Programmierung mithilfe des Parsers aus der Anwendung ausgeschlossen werden könnte.

Tatsächlich können alle fehlenden Funktionen durch eine angemessene Vorbereitung des Dokuments ausgeglichen werden. Sie können alle mit den fehlenden Funktionen verbundenen Arbeiten (falls gewünscht) vom Quick-and-Dirty-Parser in den Dokumentvorbereitungsschritt verlagern.

Parser-Funktionalität

Genug davon, was der Parser nicht kann. Was kann ich tun?

  • Es erkennt alle Start- und End-Tags der Elemente
  • Es werden Attribute aufgelistet, bei denen Attributwerte in einfache oder doppelte Anführungszeichen gesetzt werden können
  • Es erkennt das Konstrukt
  • Es erkennt die Standardentitäten: &, <,>, "und 'sowie numerische Entitäten
  • Es ordnet Linien in endend \r\nund \rzu \nauf Eingang, in Übereinstimmung mit der XML - Spezifikation, Abschnitt 2.11

Der Parser führt nur eine minimale Fehlerprüfung durch und gibt eine Exceptionunerwartete Syntax aus, z. B. unbekannte Entitäten. Wiederum wird dieser Parser jedoch nicht validiert. Es wird davon ausgegangen, dass das empfangene XML-Dokument gültig ist.

So verwenden Sie dieses Paket

Die Verwendung des schnellen und schmutzigen XML-Parsers ist einfach. Implementieren Sie zunächst die DocHandlerSchnittstelle. Analysieren Sie dann einfach eine Datei mit dem Namen config.xml:

DocHandler doc = neuer MyDocHandler (); QDParser.parse (doc, neuer FileReader ("config.xml"));

Der Quellcode enthält zwei Beispiele für vollständige DocHandlerImplementierungen. Der erste DocHandlerAufruf ruft Reportereinfach alle Ereignisse auf, System.outwährend er sie liest. Sie können die Reportermit der Beispiel-XML-Datei ( config.xml) testen .

Das zweite und komplexere Beispiel Confaktualisiert Felder in einer vorhandenen Datenstruktur, die sich im Speicher befindet. Confverwendet das java.lang.reflectPaket, um Felder und Objekte zu finden, die in beschrieben sind config.xml. Wenn Sie dieses Programm ausführen, werden Diagnoseinformationen gedruckt, die Ihnen mitteilen, welche Objekte wie aktualisiert werden. Es werden Fehlermeldungen ausgegeben, wenn die Konfigurationsdatei aufgefordert wird, nicht vorhandene Felder zu aktualisieren.

Ändern Sie dieses Paket

Sie möchten dieses Paket wahrscheinlich für Ihre eigene Anwendung ändern. Sie können benutzerdefinierte Entitätsdefinitionen hinzufügen. Zeile 180 QDParser.javaenthält den Kommentar "Benutzerdefinierte Entitätsdefinitionen hier einfügen".

Sie können auch die Funktionalität der Finite-State-Machine erweitern und die hier ausgeschlossene Funktionalität wiederherstellen. In diesem Fall sollte die geringe Größe des Quellcodes diese Aufgabe relativ einfach machen.

Halte es klein

Die QDParserKlasse belegt ca. 3 KB, nachdem Sie sie kompiliert und in eine JAR-Datei gepackt haben. Der Quellcode selbst mit Kommentaren umfasst etwas mehr als 300 Zeilen. Dies sollte für die meisten Anwendungen mit eingeschränktem Speicherplatz klein genug sein und genügend XML-Spezifikationen enthalten, um die meisten nützlichen Funktionen nutzen zu können.

Steven Brandt hat einen Doktortitel in Computerastrophysik und ist Inhaber von Stevesoft, einem Unternehmen, das Software für reguläre Ausdrücke für Java verkauft.

Erfahren Sie mehr über dieses Thema

  • Der Quellcode für diesen Tipp

    //images.techhive.com/downloads/idge/imported/article/jvw/2002/05/xmlparsertip.zip

  • Die XML-Spezifikation am W3C

    //www.w3.org/TR/2000/REC-xml-20001006

  • Die SAX-Website

    //sax.sourceforge.net

  • Die JAXP-Website

    //java.sun.com/xml/jaxp/index.html

  • Die J2ME-Website

    //java.sun.com/j2me/

  • Durchsuchen Sie den Java- und XML- Abschnitt des aktuellen Index von JavaWorld

    //www.javaworld.com/channel_content/jw-xml-index.shtml

  • Zeigen Sie alle vorherigen Java-Tipps an und senden Sie Ihre eigenen

    //www.javaworld.com/javatips/jw-javatips.index.html

  • Lernen Sie Java von Grund auf in Javaworld‘ s Java 101 Säule

    //www.javaworld.com/javaworld/topicalindex/jw-ti-java101.html

  • Java - Experten beantworten Ihre härtesten Java Fragen in Javaworld‘ s Java Q & A - Säule

    //www.javaworld.com/javaworld/javaqa/javaqa-index.html

  • Durchsuchen Sie den Java- Kernabschnitt des aktuellen JavaWorld- Index

    //www.javaworld.com/channel_content/jw-core-index.shtml

  • Bleiben Sie auf unsere Tipps ‚N Tricks durch zu abonnieren Javaworld‘ kostenlos s wöchentlichen E - Mail - Newsletter

    //www.javaworld.com/subscribe

  • Lernen Sie die Grundlagen der clientseitige Java in Javaworld‘ s Java Anfänger Diskussion. Zu den Kernthemen gehören die Java-Sprache, die Java Virtual Machine, APIs und Entwicklungstools

    //forums.idg.net/[email protected]@.ee6b804

  • Unter .net finden Sie eine Fülle von IT-Artikeln aus unseren Schwesterpublikationen

Diese Geschichte "Java-Tipp 128: Erstellen eines schnellen und schmutzigen XML-Parsers" wurde ursprünglich von JavaWorld veröffentlicht.