Die ParserFactory

Bisher habe ich euch nur einen Weg gezeigt, einen Parser zu instantiieren, nämlich

Parser parser = new Parser();

So, oder so ähnlich hat das für alle Parser ausgesehen. Das ist ja nun weiter nichts besonderes.

Es gibt aber noch einen zweiten Weg einen Parser zu instantiieren. Dieser Weg führt (ich weiß, daß das eine Überraschung nach dieser Überschrift ist) über die Klasse ParserFactory. Diese Klasse bietet eine einfache und bequeme Möglichkeit ein Parser-Objekt zu erzeugen, auch wenn innerhalb einer Anwendung verschiedene Parser benutzt werden sollen.

Was meine ich nun damit? Nun, ich denke, daß wird spätesten nach einem Beispiel klar. Aber zunächst möchte ich die Benutzung dieser Klasse näher erklären.

Parser parser = ParserFactory.makeParser(parserName);

Diese Zeile erzeugt einen Parser, soviel dürfte klar sein. Aber welchen Parser? Das hängt von dem String ab, den ihr makeParser übergebt. Zum Beispiel wird mit "com.ibm.xml.parsers.SAXParser" ein SAX-Parser von IBM erzeugt, und mit "com.sun.xml.parser.Parser" das entsprechende Pendant von Sun. Zurückgegeben wird aber in jedem Fall ein Objekt vom Typ org.xml.sax.Parser. Das bedeutet jetzt aber nicht, daß ihr nicht auch DOM-Parser erzeugen könnt. Mit "com.ibm.xml.parsers.DOMParser" wäre das zum Beispiel der Fall.

Kommen wir nun zum versprochenen Beispiel. Was würde sich da besser eignen, als ein kleiner Benchmark? Um die Übersichtlichkeit zu wahren, habe ich nur die verschiedenen SAX-Parser verglichen, also jeweils den validierenden und den nichvalidierenden SAX-Parser von Sun und IBM. Beim Aufruf des Programms, wird ein Dateiname mit angegeben, das zu parsende XML-Dokument.

Dieses Dokument wird nun mit jedem Parser 10 mal geparst. Das Dokument sollte auf jeden Fall valide sein, und ausreichen groß, um nicht in ein paar Millisekunden durchgeparst werden zu können. Die Parser werden der Reihe nach aufgerufen, und das 10 mal, anstatt einen Parser 10 mal parsen zu lassen, und das bei jedem Parser. Das hat den Vorteil, daß sich eventuelle Änderungen der Voraussetzungen (Starten von Programmen auf dem Computer etc.) weniger stark verzerrend auswirken.

Ausgegeben wird dann für jeden Parser ein Durchschnittswert der benötigten Zeit, sowie das Minimum und das Maximum.

import org.xml.sax.*;
import org.xml.sax.helpers.ParserFactory;
import java.util.Date;

public class TimeTest
{
    public static void main(String[] args)
    {
        TimeTest time = new TimeTest();
        time.test(args[0]);
    }


    private long parseIt(String file, String parserName)
    {
        long time = 0;

        try
        {
            long start = (new Date()).getTime();
            Parser parser = ParserFactory.makeParser(parserName);

            if (parserName.startsWith("com.sun"))
                parser.parse(com.sun.xml.parser.Resolver.createInputSource
                                                (new java.io.File(file)));
            else
                parser.parse(file);

            time = (new Date()).getTime() - start;
        }
        catch (Exception e)
        {
            System.err.println("Fehler: ");
            System.err.println(e);
        }

        return time;
    }


    public void test(String file)
    {
        long[] ibmSAX    = new long[] {Long.MAX_VALUE, Long.MIN_VALUE, 0};
        long[] ibmSAXval = new long[] {Long.MAX_VALUE, Long.MIN_VALUE, 0};
        long[] sunSAX    = new long[] {Long.MAX_VALUE, Long.MIN_VALUE, 0};
        long[] sunSAXval = new long[] {Long.MAX_VALUE, Long.MIN_VALUE, 0};
        int anzahl = 10;
        long zeit = 0;

        for (int i = 0; i < anzahl; i++)
        {
            zeit = parseIt(file, "com.ibm.xml.parsers.SAXParser");
            if (zeit < ibmSAX[0])
                ibmSAX[0] = zeit;
            if (zeit > ibmSAX[1])
                ibmSAX[1] = zeit;
            ibmSAX[2] += (zeit / anzahl);

            zeit = parseIt(file, "com.ibm.xml.parsers.ValidatingSAXParser");
            if (zeit < ibmSAXval[0])
                ibmSAXval[0] = zeit;
            if (zeit > ibmSAXval[1])
                ibmSAXval[1] = zeit;
            ibmSAXval[2] += (zeit / anzahl);

            zeit = parseIt(file, "com.sun.xml.parser.Parser");
            if (zeit < sunSAX[0])
                sunSAX[0] = zeit;
            if (zeit > sunSAX[1])
                sunSAX[1] = zeit;
            sunSAX[2] += (zeit / anzahl);

            zeit = parseIt(file, "com.sun.xml.parser.ValidatingParser");
            if (zeit < sunSAXval[0])
                sunSAXval[0] = zeit;
            if (zeit > sunSAXval[1])
                sunSAXval[1] = zeit;
            sunSAXval[2] += (zeit / anzahl);

            System.out.println(i + 1 + ". Durchlauf geschafft…");
        }

        System.out.println("IBM SAX           : av: " + ibmSAX[2]
         + "\t\tmin: " + ibmSAX[0]    + "\t\tmax: " + ibmSAX[1]);
        System.out.println("Sun SAX           : av: " + sunSAX[2]
         + "\t\tmin: " + sunSAX[0]    + "\t\tmax: " + sunSAX[1]);
        System.out.println("validating IBM SAX: av: " + ibmSAXval[2]
         + "\t\tmin: 2 + ibmSAXval[0] + "\t\tmax: " + ibmSAXval[1]);
        System.out.println("validating Sun SAX: av: " + sunSAXval[2]
         + "\t\tmin: " + sunSAXval[0] + "\t\tmax: " + sunSAXval[1]);
    }
}

Eine Sache, die vielleicht nicht auf den ersten Blick klar wird, möchte ich noch schnell erklären. Zu jedem Parser gehört ein Feld, in dem die Zeiten gespeichert werden. Auf dem ersten Index wird das Minimum gespeichert, auf dem zweiten Index das Maximum, und auf dem dritten der Durchschnitt.

Das Ergebnis dieses kleinen Benchmarks gebe ich hier natürlich nicht bekannt, ich will ja, daß ihr das auch mal selbst ausprobiert! ;-)

zurück                weiter

nach oben