Heiner Kücker

XML Really Pull Parser

Home

Java-Seite

   Bit Packed Array

   ASM Improved

   heterogene
   Map, HMap

   Constraint
   Code Generator

   JSP WorkFlow
   PageFlow FlowControl
   Page Flow Engine
   Web Flow Engine
   Control_and_Command

   JSP_Spreadsheet

   Code-Generator
   für Option-Either-Stil
   in Java

   verbesserter
   Comparator

   Fluent-Interface
   Code-Generator
   auf Basis
   einer Grammatik

   Visitor mit Multidispatch

   for-Schleife mit
   yield-return

   Kognitions-Maschine
   semantisches Netz

   Domain Parser

   Codegenerator_für
   hierarchische
   Datenstrukturen

   Expression_Engine
   Formula_Parser

   Thread Preprocessor

   State Transition Engine

   AspectJ

   Java_Explorer

   DBF_Library

   Kalender_Applet

   SetGetGen

   BeanSetGet

   CheckPackage

   LineNumbers

   GradDms

   Excel-Export

   StringTokenizer

   JspDoc

   JspCheck

   JSP-Schulung
   Java Server Pages
   Struts

   Ascii-Tabellen-
   Layouter

   Ascii-Baum-
   Layouter

   Ascii-Art-Fluss-
   Diagramm-
   Parser

   AsciiArt
   AssignmentMatrix
   Layouter

   StringSerial

   Silbentrennung

   JDBC_Schlüssel-
   Generierung

   bidirektional/
   unidirektional
   gelinkte Liste

   Java_Sitemap
   Generator

   XmlBuilder

   RangeMap

   StringFormatter

   VersionSafe
   XCopy

   JTextField

   CommandLine-
   ParamReader

   Bitmap-Grafik

   MultiMarkable-
   Buffered-
   InputStream

   JavaCache

   JdomUtil

   CollectionUtil

   XML Really
   Pull Parser

   Log-Filter

   Remote-Protokoll

   Sudoku-Generator

   Delegation statt
   Mehrfachvererbung

   Disjunct
   Interval Set

   WebCam_Demo

   Weiterentwicklung_Java

Alaska-XBase++-Seite

Projekte

Philosophien
Techniken


Konzepte

Sudoku

Kontakt /
Impressum


Links

SiteMap





Letzte Aktualisierung:
15.06.2007
XML Really Pull Parser

Prototyp für einen XML-Parser, dessen Anwendugscode geanau die Struktur des XML-Dokumentes wiederspiegelt und keine Stack-Logik benötigt.

XML really pull parser
----------------------

Neben den SAX- und DOM-XML-Parsern gibt es die sogenannten XML-
Pull-Parser oder Streaming-Parser (StAX).

Beim XML-Pull-Parser wird noch nach Cursor- oder Iterator-
ähnlicher Verarbeitung unterschieden.

Die meisten XML-Pull-Parser werden folgendermassen angewendet
(Cursor-Verfahren):

while( parser.hasNext() ) {
    int event = parser.next();
    switch (event) {
        case XMLStreamConstants.END_DOCUMENT:
            System.out.println("END_DOCUMENT");
            parser.close();
            break;
        case XMLStreamConstants.START_ELEMENT:
            System.out.println("START_ELEMENT: " + parser.getLocalName() );
            for( int i = 0; i < parser.getAttributeCount(); i++ )
               System.out.println("Attribut: " + parser.getAttributeLocalName(i)
                                + " Wert: " + parser.getAttributeValue(i));
                                break;
        case XMLStreamConstants.CHARACTERS:
            if( !parser.isWhiteSpace() )
                System.out.println("CHARACTERS: " + parser.getText() );
            break;
        case XMLStreamConstants.END_ELEMENT:
            System.out.println("END_ELEMENT: " + parser.getLocalName() );
            break;
        default:
            break;
    }
}

Der Parser liefert beim Verarbeiten eine Reihe von Events.
Es gibt verschiedene Eventtypen.

START_DOCUMENT
END_DOCUMENT
START_ELEMENT
END_ELEMENT
CHARACTERS
ENTITY_REFERENCE
DTD
COMMENT
PROCESSING_INSTRUCTION

Zum Verarbeiten verschachtelter Strukturen muss eine Stack-Logik
aufgebaut werden.

Ich verstehe unter Pull-Parsing etwas anderes. Für eine
dreistufige Hierachie

 Haus -> Etage -> Wohnung

verwendet man die Lösung, welche naheliegend ist, nämlich drei
verschachtelte Schleifen (imperative Programmierung statt
deklarativer oder eventgetriebener Programmierung).

Deshalb habe ich hier mal einen anders aufgebauten XML-Parser,
XML-Really-Pull-Parser, prototypisch implementiert. Er ist sehr
untolerant bezüglich Fehlern oder Auslegungen im XML-Dokument,
dafür kommt er aber mit sehr wenig Ressourcen aus, weil zum
Beispiel unterschiedliche Reihenfolgen von Attributen nicht
erlaubt sind.

CDATA und innere DTD sind (noch) nicht implementiert, wie gesagt,
es ist ein Prototyp.

Das Parser-Anwendungsprogramm (das Programm welches das
konkretete XML-Dokument abarbeitet und die XRPP-Lib benutzt)
arbeitet sich vom Anfang an durch das XML-Dokument.

Die Struktur des XML spiegelt sich in der Struktur des Codes
wieder.

Irgendwelche Stack-Strukturen sind nicht nötig. Als Stack dient
der Java-Stack (lokale Variable, Parameter).

Optionale Element oder Attribute kosten zusätzlichen Code und
Performance. Andererseits werden bei einer stabilen XML-Struktur
sehr wenig Ressourcen verbraucht.

Beispiel für die Anwendung des XML Really Pull Parser
-----------------------------------------------------

Links die XML-Datei 'rss.xml' dargestelt und rechts der entsprechende Java-Quelltext zum Parsen 'TestRssXml.java'.

Wie man beim links rechts scrollen sehen kann, entspricht die Struktur des Java-Codes zum Parsen genau
der Struktur des XML-Dokumentes.

Dadurch ist das Programmieren eines XML-Parsers für ein bestimmtes festglegtes XML-Format sehr einfach.

rss.xml                                                               | TestRssXml.java
                                                                      |
<?xml version="1.0" encoding="ISO-8859-1"?>                           | parser.skipXmlDeclaration();
                                                                      |
<!DOCTYPE rss PUBLIC "-//Netscape Communications//DTD RSS 0.91//EN"   | parser.skipDoctypeDeclaration();
              "http://my.netscape.com/publish/formats/rss-0.91.dtd">  |
<rss                                                                  | parser.forceElementStart( "rss".getBytes() );
  version="0.91">                                                     | parser.getAttribute( "version".getBytes() );
                                                                      |
                                                                      | parser.forceElementBody();
                                                                      | {
  <channel>                                                           |   parser.forceElementStart( "channel".getBytes() );
                                                                      |   parser.forceElementBody();
                                                                      |   {
    <title>mars</title>                                               |     parser.getElementBodyWithStartAndEndTag( "title".getBytes() );
    <link>http://www.example.com/mars</link>                          |     parser.getElementBodyWithStartAndEndTag( "link".getBytes() );
    <description>Developer news from the MARS community</description> |     parser.getElementBodyWithStartAndEndTag( "description".getBytes() );
    <language>en-us</language>                                        |     parser.getElementBodyWithStartAndEndTag( "language".getBytes() );
    <copyright>Copyright 2999-3001, MARS team.</copyright>            |     parser.getElementBodyWithStartAndEndTag( "copyright".getBytes() );
    <managingEditor>editor@example.com</managingEditor>               |     parser.getElementBodyWithStartAndEndTag( "managingEditor".getBytes() );
    <webMaster>webmaster@example.com</webMaster>                      |     parser.getElementBodyWithStartAndEndTag( "webMaster".getBytes() );
                                                                      |
    <image>                                                           |     parser.forceElementStart( "image".getBytes() );
                                                                      |     parser.forceElementBody();
                                                                      |     {
      <title>mars</title>                                             |       parser.getElementBodyWithStartAndEndTag( "title".getBytes() );
      <url>http://www.example.com/images/mynetscape3188.gif</url>     |       parser.getElementBodyWithStartAndEndTag( "url".getBytes() );
      <link>http://www.example.com</link>                             |       parser.getElementBodyWithStartAndEndTag( "link".getBytes() );
      <width>88</width>                                               |       parser.getElementBodyWithStartAndEndTag( "width".getBytes() );
      <height>31</height>                                             |       parser.getElementBodyWithStartAndEndTag( "height".getBytes() );
      <description>News, and so on</description>                      |       parser.getElementBodyWithStartAndEndTag( "description".getBytes() );
                                                                      |     }
    </image>                                                          |     parser.forceElementStopNoEmpty( "image".getBytes() );
                                                                      |
    <item>                                                            |     while ( parser.isElementStart( "item".getBytes() ) )
                                                                      |     {
                                                                      |       parser.forceElementStart( "item".getBytes() );
                                                                      |       parser.forceElementBody();
                                                                      |       |
      <title>MARS 1.0 Released</title>                                |         parser.getElementBodyWithStartAndEndTag( "title".getBytes() );
      <link>http://www.example.com/read?item=3322323</link>           |         parser.getElementBodyWithStartAndEndTag( "link".getBytes() );
      <description>The MARS survival toolkit.</description>           |         parser.getElementBodyWithStartAndEndTag( "description".getBytes() );
                                                                      |       }
    </item>                                                           |       parser.forceElementStopNoEmpty( "item".getBytes() );
                                                                      |     }
                                                                      |   }
  </channel>                                                          |   parser.forceElementStopNoEmpty( "channel".getBytes() );
                                                                      | }
</rss>                                                                | parser.forceElementStopNoEmpty( "rss".getBytes() );
                                                                      |
TODO
Entwickeln eines Java-Programmes, zum Erzeugen des Parser-Codes
aus einem Beispiel-XML, wobei mehrfach mögliche Elemente jeweils
mindestens zweimal im Beispiel-XML notiert sein müssen, damit der
Code-Generator erkennt, dass sich das Element wiederholen kann.

Weiterführende Überlegung

Die Entscheidung für einen stream-baiserten Parser (SAX, Stax usw), statt eines document-basierten Parsers, zwingt dem Entwickler die Arbeitsweise des jeweiligen Parsers auf.
Viel angenehmer wäre ein Parser, der es erlaubt grosse Datenmengen stream-basiert einzulesen, aber für ein bestimmtes Elemente einen DOM-Abschnitt festzulegen.
Dieser Abschnitt (ein bestimmtes Element) erlaubt dann partielles freies Navigieren in den XML-Daten.
Im Speicher muss nur der jeweilige DOM-Abschnitt gehalten werden.
Dies wäre ein guter Kompromiss zwischen Speicherbedarf und freier Navigierbarkeit und würde die Anwendung des Parsers erleichtern.
Ein Beispiel wäre ein mehrere Mega-Byte grosser Produkt-Katalog, aus dem jeweils das Artikel-Element als DOM-Area geschnitten wird.

Siehe hierzu auch XmlBuilder, XmlDocument

Siehe hierzu auch JdomUtil

Download der Quelldateien Xrpp.zip

Achtung: Erweiterungen und Fixes stelle ich ohne Historie und ohne Ankündigung hier bereit.
Deshalb am besten immer die letzte Version runterladen.

Lizenzbedingungen:

Die Programme, Quelltexte und Dokumentationen können ohne irgendwelche Bedingungen kostenlos verwendet werden.
Sie sind Freeware und Open Source. Für Fehler und Folgen wird keinerlei Haftung übernommen.

Hinweise zur Fehlerbeseitigung und Verbesserung sind mir willkommen.

Ich freue mich auch über Feedback bezüglich der erfolgreichen Verwendung meiner Sourcen.

Bei Fragen helfe ich gern mit Hinweisen oder zusätzlicher Dokumentation, falls ich dafür Zeit habe.