# Probleme beim Parsen eines gefilterten XML-Dokuments



## megalomaniac (30. Jun 2010)

Hallo zusammen,

ich verzweifle gerade ein klein wenig und hoffe auf gedankliche Unterstützung.

Die Situation:
Ich betreibe ein Programm, dass den Inhalt von XML-Dateien weiterverarbeitet. Die XML-Dateien werden in Form eines InputStreams an den Parser (SAX und DOM einsetzbar) übergeben. Da ich mich aber nicht darauf verlassen kann, dass die XML-Dateien well-formed sind, habe ich einen FilterInputStream (XmlFilterInputStream.java) dazwischengeschaltet, der den Inhalt nach bestimmten Regeln umsetzt, z.B. & -> &amp;. Das funktioniert prinzipiell auch problemlos, d.h. der Filter setzt die Zeichen genau so um, wie sie umgesetzt werden sollen.

Allerdings - und das ist mein eigentliches Problem - scheint der Parser den Inhalt nicht Zeichen für Zeichen durchzugehen, sondern hin und wieder ÜBERSPRINGT er bestimmte Zeichen einfach, indem er nicht die Methoden read() bzw. read(byte[]), sondern read(byte[], int, int) mit gesetztem offset aufruft, was dazu führt, dass bestimmte Zeichen einfach ignoriert werden. Mir ist nicht klar warum er das tut, die Folge davon ist jedenfalls, dass das Format der XML-Datei zerstört wird (z.B. weil öffnendes und schließendes Tag nicht mehr zueinander passen). Das passiert nicht bei jeder Datei, nur bei einigen wenigen, aber eine stichhaltige Regelmäßigkeit konnte ich dabei bisher nicht entdecken.

Der Quelltext sieht in etwa so aus:

```
// Gegeben: InputStream is
XmlFilterInputStream filterStream = new XmlFilterInputStream(is);
InputSource inSource = new InputSource(filterStream);
inSource.setEncoding("UTF-8");
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
w3cDocument = builder.parse(inSource);
```

Die Dateien liegen im UTF-8-Format vor. Ich muss das Format explizit im InputSource-Objekt setzen, da ich sonst immer folgende Exception vom Parser bekomme:
JDomInitialisationException: Problem while parsing: Document root element is missing.!

Hat jemand eine Idee, was die Ursache für mein Problem sein könnte? Ich hoffe ich habe die Situation verständlich erklären können.

Danke und Gruß,
megalomaniac


----------



## Noctarius (30. Jun 2010)

Wenn ich mich recht erinnere nutzt der Sax Parser intern einen Reader und keinen InputStream. Vielleicht bringt dich das auf die richtige Spur.


----------



## megalomaniac (1. Jul 2010)

Danke für die Antwort, aber leider hilft mir das nicht weiter...

Ich habe allerdings herausgefunden, dass es irgendetwas mit der UTF-8-Codierung zu tun haben muss. Es gibt im Großen und Ganzen zwei verschiedene Arten von XML-Dateien, die einen sind in UTF-8 codiert, die anderen in ISO-8859-1. Zumindest steht das so im XML-Header der Datei. Die Information wird vom Programm ausgelesen und die Codierung entsprechend im DataSource-Objekt gesetzt.

Ergänzung zum oben genannten Code also:

```
inSource.setEncoding(filterStream.getEncoding());
```

Das oben beschriebene Problem beim Parsen tritt offenbar nur bei den Dateien auf, die in UTF-8 codiert sind. Vielleicht BEHAUPTET das XML-File nur in UTF-8 codiert zu sein, ist aber eigentlich ein ganz normales ANSI-XML. Mal prüfen...


----------



## Noctarius (1. Jul 2010)

Vielleicht hilft dir hier auch einer der Posts weiter (z.B. der Dritte) I need to parse non well-formed xml data (HTML) - Stack Overflow


----------



## megalomaniac (9. Jul 2010)

Ich habe aus meinen XmlFilterInputStream jetzt Reader gemacht (abgeleitet von InputStreamReader), was das vorherige Problem beseitigt hat. Jetzt habe ich allerdings ein anderes:


```
jdomDocument = saxBuilder.build(new XmlFilterInputStreamReader(is));
```

Und zwar übergebe ich dem Reader die XML-Datei in Form eines InputStreams (is). Wie oben schon erwähnt können die XML-Dateien in den Formaten UTF-8 und ISO-8859-1 vorliegen. Mit Sicherheit bestimmen kann ich das nur durch das Auslesen des XML-Headers, wo das Encoding definiert wird. 

An dieser Stelle bekomme ich jetzt ein Henne-Ei-Problem, weil ich das Encoding im Konstruktor der Superklasse InputStreamReader setzen muss (ein nachträgliches Setzen des Encodings ist offenbar nicht möglich), ich den Reader aber erstmal instanziiert haben muss, um überhaupt auf den Inhalt des InputStreams zugreifen zu können.

Ich möchte unbedingt vermeiden den InputStream wegen dem zu ermittelnden Encoding erst "anlesen" zu müssen, um ihn anschließend wegzuwerfen und neu zu holen. Jemand eine Idee wie man das eleganter hinbekommen könnte?


----------



## Noctarius (9. Jul 2010)

Zur Not in beiden Encoding auslesen und schauen ob was sinnvolles raus kommt. Du weißt ja wie der Header aussehen muss.


----------



## megalomaniac (12. Jul 2010)

Hmm, keine so Gute Idee.

Das Problem ist, dass die XML-Dateien mitunter sehr groß sein können (> 200 MB) und von dem Programm im Normalfall viele Tausend solcher Dateien sequentiell durchlaufen werden. Ein eklatanter Verlust an Durchsatzperformanz wäre die Folge eines solchen Trial-and-Error-Verfahrens...


----------

