Discussion:
Probleme mit Sax-Parser
(zu alt für eine Antwort)
Dennis Engelbrecht
2003-12-18 12:29:25 UTC
Permalink
Hallo,
ich habe folgendes Problem:
ich moechte eine XML-Datei parsen um noch einen Tag einzufuegen. Dazu
muss ich erst eine CSV-Datei durchgehen um mir die Artikelnummern und
Daten zu holen. Dieses speichere ich in einer Hashmap weg. Jetzt
wollte ich in der endElement-Funktion des Defaulthandlers in diese
Hashmap reinschauen ob die Nummer vorhanden ist. Das Problem ist die
Map ist leer. Sobald ich mit den Parsen der XML-Datei fertig bin und
noch mal in die Map schaue gibt es die Einträge aber wieder. Weiss
einer woran das liegt und wie ich das Problem lösen kann?

Danke
Dennis
Lutz Horn
2003-12-18 12:56:06 UTC
Permalink
Hallo,
Post by Dennis Engelbrecht
ich moechte eine XML-Datei parsen um noch einen Tag einzufuegen.
Dazu muss ich erst eine CSV-Datei durchgehen um mir die
Artikelnummern und Daten zu holen. Dieses speichere ich in einer
Hashmap weg. Jetzt wollte ich in der endElement-Funktion des
Defaulthandlers in diese Hashmap reinschauen ob die Nummer
vorhanden ist. Das Problem ist die Map ist leer. Sobald ich mit
den Parsen der XML-Datei fertig bin und noch mal in die Map schaue
gibt es die Einträge aber wieder. Weiss einer woran das liegt und
wie ich das Problem lösen kann?
Ohne Code wird das schwierig. Es klingt aber so, als ob die Hashmap dem
Defaulthandler nicht richtig übergeben wird.

Lutz
--
no sig
Dennis Engelbrecht
2003-12-23 11:04:48 UTC
Permalink
Post by Dennis Engelbrecht
Hallo,
Post by Dennis Engelbrecht
ich moechte eine XML-Datei parsen um noch einen Tag einzufuegen.
Dazu muss ich erst eine CSV-Datei durchgehen um mir die
Artikelnummern und Daten zu holen. Dieses speichere ich in einer
Hashmap weg. Jetzt wollte ich in der endElement-Funktion des
Defaulthandlers in diese Hashmap reinschauen ob die Nummer
vorhanden ist. Das Problem ist die Map ist leer. Sobald ich mit
den Parsen der XML-Datei fertig bin und noch mal in die Map schaue
gibt es die Einträge aber wieder. Weiss einer woran das liegt und
wie ich das Problem lösen kann?
Ohne Code wird das schwierig. Es klingt aber so, als ob die Hashmap dem
Defaulthandler nicht richtig übergeben wird.
Lutz
okay dann will ich mal den Code abliefern. Falls es verbesserungen
gibt immer her damit bin nämlich noch neu in Java und für Tipps immer
dankbar.

public class TagEinfuegen extends DefaultHandler implements Runnable{
private String xmlFilename;
private String neuFilename;
private String datenFilename;
private String nachTag;
private String neuerTag;
private int anzTabs;

public HashMap map = new HashMap();

private BufferedReader br;
private BufferedWriter bw;

private boolean inArticleAid = false;
private String artID = new String("");

public TagEinfuegen(String xmlFilename, String neuFilename,
String datenFilename,
String nachTag,
String neuerTag, int
anzTabs){
this.xmlFilename = xmlFilename;
this.neuFilename = neuFilename;
this.datenFilename = datenFilename;
this.nachTag = nachTag;
this.neuerTag = neuerTag;
this.anzTabs = anzTabs;
new Thread( this ).start();

}

public TagEinfuegen() {
super();
}

public void run() {
makeMap();
int test;
String test2;
makeTag(map);
JOptionPane.showMessageDialog(null, "Konvertierung
fertig. ", null, JOptionPane.INFORMATION_MESSAGE);

}

public void makeMap(){
try {
br = new BufferedReader(new
InputStreamReader(
new
ProgressMonitorInputStream(null,
"Lese " + datenFilename,
new
FileInputStream(datenFilename))));
String buffer;
String values[];
while((buffer = br.readLine()) !=
null){
values = buffer.split(";");
map.put(values[0], values[1]);
}
}
catch (FileNotFoundException fnfe) {
JOptionPane.showMessageDialog(null,
"Konnte " + datenFilename + " nicht öffnen", null,

JOptionPane.ERROR_MESSAGE);
}
catch (IOException ioe){
JOptionPane.showMessageDialog(null, "Konnte "
+ datenFilename + " nicht lesen", null,

JOptionPane.ERROR_MESSAGE);
}
finally{
if(br != null){
try{
br.close();
}
catch(Exception ignored){
}
}
if (bw != null) {
try{
bw.close();
}
catch(Exception ignored) {
}
}
}

}

public void makeTag(HashMap map) {

DefaultHandler handler = new TagEinfuegen();

SAXParserFactory factory =
SAXParserFactory.newInstance();
try{
SAXParser saxParser = factory.newSAXParser();

saxParser.parse(new File(xmlFilename),
handler);
}
catch(SAXParseException spe){
spe.printStackTrace();
}catch (SAXException sxe) {
sxe.printStackTrace();
}catch (IOException ioe) {
ioe.printStackTrace();
}catch (ParserConfigurationException pce){
pce.printStackTrace();
}

}



public void startElement(String namespaceURI,
String sName,
// simple name (localName)
String qName,
// qualified name
Attributes
attrs)
throws SAXException
{
if (qName.compareTo("SUPPLIER_AID") == 0){
inArticleAid = true;
artID = "";

}
}

public void endElement(String namespaceURI,
String
sName, // simple name
String
qName // qualified name
)
throws SAXException
{
if (qName.compareTo("SUPPLIER_AID") == 0){
inArticleAid = false;
if (map.containsKey(artID)) {
} else {
}
map.get(artID);
}
}

public void characters(char buf[], int offset, int len)
throws SAXException
{
if (inArticleAid && buf != null){
artID =
artID.concat(String.valueOf(buf, offset, len));
}
}

}
michael paap
2003-12-23 12:25:18 UTC
Permalink
Post by Dennis Engelbrecht
okay dann will ich mal den Code abliefern. Falls es verbesserungen
gibt immer her damit bin nämlich noch neu in Java und für Tipps immer
dankbar.
private String artID = new String("");
private String artID = "";

tut's auch.
Post by Dennis Engelbrecht
catch(SAXParseException spe){
spe.printStackTrace();
}catch (SAXException sxe) {
sxe.printStackTrace();
}catch (IOException ioe) {
ioe.printStackTrace();
}catch (ParserConfigurationException pce){
pce.printStackTrace();
}
würde ich ganz dreist durch

} catch (Exception e) {
e.printStackTrace();
}

ersetzen.

Stringvergleiche mit
Post by Dennis Engelbrecht
if (qName.compareTo("SUPPLIER_AID") == 0) { ... }
sind ziemlich... eigenwillig. Warum nicht einfach so?

if (qName.equals("SUPPLIER_AID") { ... }
Post by Dennis Engelbrecht
public void makeTag(HashMap map) {
Warum übergibst Du die Map? Die ist doch als Attribut überall in der
Klasse verfügbar.

Zu Deinem eigentlichen Problem:

Du hast einen Konstruktor, in dem Du allerlei Attribute belegst. Dann
startest Du an dessen Ende einen Thread, in dem die run()-Methode des
gerade initialisierten Objekts ausgeführt wird. In dieser werden
makeMap() und makeTag() aufgerufen. In makeMap() wird die Map befüllt,
dann übergibst Du sie an makeTag(). Dem SAXParser übergibst Du
allerdings ein *neues* Exemplar von TagEinfügen, welches demnach eine
*leere* HashMap hat. Die Map, die Du übergibst... mit der machst Du in
der Methode überhaupt nichts.

So... und nun wird Dein SaxParser irgendwann die Methode endElement()
seines Handlers aufrufen... das ist bei Dir das neu angelegte Objekt mit
leerer HashMap, wovon Du Dich durch eine Ausgabe der Map in endElement()
leicht überzeugen kannst. Übergib stattdessen dem SaxParser "this" als
Handler, dann hast Du in endElement() auch *die* Map, die Du vorher
befüllt hast. Den parameterlosen Konstruktor kannst Du dann auch gleich
wegwerfen, denn den brauchst Du jetzt ja nicht mehr.

Hier mal Dein Code mit den diversen Änderungen. Da fehlt natürlich noch
einiges, aber zumindest solltest Du weiterkommen:

import java.io.*;
import java.util.HashMap;

import javax.swing.*;
import javax.xml.parsers.*;

import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;

public class TagEinfuegen extends DefaultHandler implements Runnable {

private String xmlFilename;
private String neuFilename;
private String datenFilename;
private String nachTag;
private String neuerTag;
private int anzTabs;
private BufferedReader br;
private BufferedWriter bw;
private boolean inArticleAid = false;
private String artID = "";
public HashMap map = new HashMap();

public TagEinfuegen(String xmlFilename, String neuFilename,
String datenFilename, String nachTag,
String neuerTag, int anzTabs) {
this.xmlFilename = xmlFilename;
this.neuFilename = neuFilename;
this.datenFilename = datenFilename;
this.nachTag = nachTag;
this.neuerTag = neuerTag;
this.anzTabs = anzTabs;
new Thread(this).start();
}

public void run() {
makeMap();
makeTag();
JOptionPane.showMessageDialog(null, "Konvertierung fertig. ",
null, JOptionPane.INFORMATION_MESSAGE);
}

public void makeMap() {
try {
br = new BufferedReader(new InputStreamReader(
new ProgressMonitorInputStream(null,
"Lese " + datenFilename,
new FileInputStream(datenFilename))));
String buffer;
String values[];
while ((buffer = br.readLine()) != null) {
values = buffer.split(";");
map.put(values[0], values[1]);
}
} catch (FileNotFoundException fnfe) {
JOptionPane.showMessageDialog(null,
"Konnte " + datenFilename + " nicht öffnen", null,
JOptionPane.ERROR_MESSAGE);
} catch (IOException ioe) {
JOptionPane.showMessageDialog(null,
"Konnte " + datenFilename + " nicht lesen", null,
JOptionPane.ERROR_MESSAGE);
} finally {
if (br != null) {
try {
br.close();
} catch (Exception ignored) {
}
}
if (bw != null) {
try {
bw.close();
} catch (Exception ignored) {
}
}
}
}

public void makeTag() {
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
SAXParser saxParser = factory.newSAXParser();
saxParser.parse(new File(xmlFilename), this);
} catch (Exception e) {
e.printStackTrace();
}
}

public void startElement(String namespaceURI, String sName,
String qName, Attributes attrs) throws SAXException {
if (qName.equals("SUPPLIER_AID")) {
inArticleAid = true;
artID = "";
}
}

public void endElement(String namespaceURI, String sName,
String qName) throws SAXException {
if (qName.equals("SUPPLIER_AID")) {
inArticleAid = false;
if (map.containsKey(artID)) {
// TODO
} else {
// TODO
}
map.get(artID);
}
}

public void characters(char buf[], int offset,
int len) throws SAXException {
if (inArticleAid && buf != null) {
artID = artID.concat(String.valueOf(buf, offset, len));
}
}
}

Gruß,
Michael
--
Die Adresse im From existiert, wird aber nicht gelesen. Daher:
Sollte ausnahmsweise eine Mail-Antwort auf ein Posting vonnöten sein,
bitte folgende Adresse verwenden: newsreply@<Absender-Domain>.
Dennis Engelbrecht
2003-12-23 13:14:41 UTC
Permalink
Post by michael paap
Post by Dennis Engelbrecht
okay dann will ich mal den Code abliefern. Falls es verbesserungen
gibt immer her damit bin nämlich noch neu in Java und für Tipps immer
dankbar.
private String artID = new String("");
private String artID = "";
tut's auch.
Post by Dennis Engelbrecht
catch(SAXParseException spe){
spe.printStackTrace();
}catch (SAXException sxe) {
sxe.printStackTrace();
}catch (IOException ioe) {
ioe.printStackTrace();
}catch (ParserConfigurationException pce){
pce.printStackTrace();
}
würde ich ganz dreist durch
} catch (Exception e) {
e.printStackTrace();
}
ersetzen.
Stringvergleiche mit
Post by Dennis Engelbrecht
if (qName.compareTo("SUPPLIER_AID") == 0) { ... }
sind ziemlich... eigenwillig. Warum nicht einfach so?
if (qName.equals("SUPPLIER_AID") { ... }
Post by Dennis Engelbrecht
public void makeTag(HashMap map) {
Warum übergibst Du die Map? Die ist doch als Attribut überall in der
Klasse verfügbar.
Du hast einen Konstruktor, in dem Du allerlei Attribute belegst. Dann
startest Du an dessen Ende einen Thread, in dem die run()-Methode des
gerade initialisierten Objekts ausgeführt wird. In dieser werden
makeMap() und makeTag() aufgerufen. In makeMap() wird die Map befüllt,
dann übergibst Du sie an makeTag(). Dem SAXParser übergibst Du
allerdings ein *neues* Exemplar von TagEinfügen, welches demnach eine
*leere* HashMap hat. Die Map, die Du übergibst... mit der machst Du in
der Methode überhaupt nichts.
So... und nun wird Dein SaxParser irgendwann die Methode endElement()
seines Handlers aufrufen... das ist bei Dir das neu angelegte Objekt mit
leerer HashMap, wovon Du Dich durch eine Ausgabe der Map in endElement()
leicht überzeugen kannst. Übergib stattdessen dem SaxParser "this" als
Handler, dann hast Du in endElement() auch *die* Map, die Du vorher
befüllt hast. Den parameterlosen Konstruktor kannst Du dann auch gleich
wegwerfen, denn den brauchst Du jetzt ja nicht mehr.
Hier mal Dein Code mit den diversen Änderungen. Da fehlt natürlich noch
Gruß,
Michael
Besten Dank.

Das war genau der Denkanstoss der mir gefehlt hat. Auf sowas kann man
auch selber kommen. Aber wenn man alle möglichen und Unmöglichen
Sachen schon ausprobiert hat sieht man sowas ab und an nicht.
Habe es eingebaut und es funktioniert.

Vielleicht ist hier ja auch noch einer der mir ne Verständnisfrage
beantworten kann.
Wieso geht folgendes:

SAXParser saxParser = factory.newSAXParser();
saxParser.parse(new File(xmlFilename), this);

Dieses aber nicht:
SAXParser saxParser = factory.newSAXParser();
saxParser.parse(new ProgressMonitorInputStream(null,
"Lese " + xmlFilename,
new FileInputStream(xmlFilename)), this);

Hier bekomm ich immer ne schöne Exception
org.xml.sax.SAXParseException: Relative URI
"bmecat_new_catalog_1_2.dtd"; kann nicht ohne eine Basis-URI aufgelöst
werden.
at org.apache.crimson.parser.Parser2.fatal(Parser2.java:3339)
at org.apache.crimson.parser.Parser2.fatal(Parser2.java:3333)
at
org.apache.crimson.parser.Parser2.resolveURI(Parser2.java:2915)
at
org.apache.crimson.parser.Parser2.maybeExternalID(Parser2.java:2887)
at
org.apache.crimson.parser.Parser2.maybeDoctypeDecl(Parser2.java:1276)
at
org.apache.crimson.parser.Parser2.parseInternal(Parser2.java:623)
at org.apache.crimson.parser.Parser2.parse(Parser2.java:333)
at
org.apache.crimson.parser.XMLReaderImpl.parse(XMLReaderImpl.java:448)
at javax.xml.parsers.SAXParser.parse(SAXParser.java:345)
at javax.xml.parsers.SAXParser.parse(SAXParser.java:143)
at addtags.TagEinfuegen.makeTag(TagEinfuegen.java:128)
at addtags.TagEinfuegen.run(TagEinfuegen.java:75)
at java.lang.Thread.run(Thread.java:534)

Hab mich schon im Internet dumm und dusselig gesucht aber irgendwie
nix gescheites gefunden.
Ich fand die möglichkeit mit dem Progressbar eigentlich recht schick,
da die Files die ich durchsuchen möchte/muss teilweise über 100MB
gross sind.
Wäre super wenn ihr mir hier bei auch noch helfen könntet.
Es geht zwar auch ohne aber mit ist doch schicker.

Danke
Dennis
michael paap
2003-12-23 13:33:16 UTC
Permalink
Post by Dennis Engelbrecht
Vielleicht ist hier ja auch noch einer der mir ne Verständnisfrage
beantworten kann.
SAXParser saxParser = factory.newSAXParser();
saxParser.parse(new File(xmlFilename), this);
SAXParser saxParser = factory.newSAXParser();
saxParser.parse(new ProgressMonitorInputStream(null,
"Lese " + xmlFilename,
new FileInputStream(xmlFilename)), this);
[...]
Post by Dennis Engelbrecht
Hier bekomm ich immer ne schöne Exception
org.xml.sax.SAXParseException: Relative URI
"bmecat_new_catalog_1_2.dtd"; kann nicht ohne eine Basis-URI aufgelöst
werden.
Huh. Keine Ahnnung und ehrlich gesagt gerade keinen Nerv, das
auszuprobieren. Da müsste man sich schlimmstenfalls wohl mal zur
Laufzeit durch die ganzen Aufrufe durchwühlen, und nachsehen, mit
welchen URLs da hantiert wird und warum. Seltsam ist, dass das Problem
die DTD zu sein scheint... da sollte es doch nun wirklich egal sein, aus
welchem Stream das XML gelesen wird, zumal es laut Deiner Aussage ohne
den PMIS ja geht.

Bist Du *sicher*, dass Du sonst nichts verändert hast? Also so *richtig*
sicher? Hast Du nachgesehen? *g*

Unabhängig davon solltest Du auf jeden Fall einen BufferedInputStream um
den PMIS wickeln.

Gruß,
Michael
--
Die Adresse im From existiert, wird aber nicht gelesen. Daher:
Sollte ausnahmsweise eine Mail-Antwort auf ein Posting vonnöten sein,
bitte folgende Adresse verwenden: newsreply@<Absender-Domain>.
michael paap
2003-12-23 13:39:45 UTC
Permalink
Post by michael paap
Huh. Keine Ahnnung und ehrlich gesagt gerade keinen Nerv, das
auszuprobieren.
Ich konnte es doch nicht lassen... bei mir gibts keine Exception:

SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
MyHandler handler = new MyHandler();
parser.parse(new ProgressMonitorInputStream(null,
"Lese " + fileName,
new FileInputStream(fileName)), handler);

Das parst zumindest mal brav, die Progressbar habe ich allerdings nicht
eingebaut. Ich habe allerdings auch keine DTD drin...

Gruß,
Michael
--
Die Adresse im From existiert, wird aber nicht gelesen. Daher:
Sollte ausnahmsweise eine Mail-Antwort auf ein Posting vonnöten sein,
bitte folgende Adresse verwenden: newsreply@<Absender-Domain>.
Dennis Engelbrecht
2003-12-23 13:45:42 UTC
Permalink
Post by michael paap
Post by Dennis Engelbrecht
Vielleicht ist hier ja auch noch einer der mir ne Verständnisfrage
beantworten kann.
SAXParser saxParser = factory.newSAXParser();
saxParser.parse(new File(xmlFilename), this);
SAXParser saxParser = factory.newSAXParser();
saxParser.parse(new ProgressMonitorInputStream(null,
"Lese " + xmlFilename,
new FileInputStream(xmlFilename)), this);
[...]
Post by Dennis Engelbrecht
Hier bekomm ich immer ne schöne Exception
org.xml.sax.SAXParseException: Relative URI
"bmecat_new_catalog_1_2.dtd"; kann nicht ohne eine Basis-URI aufgelöst
werden.
Huh. Keine Ahnnung und ehrlich gesagt gerade keinen Nerv, das
auszuprobieren. Da müsste man sich schlimmstenfalls wohl mal zur
Laufzeit durch die ganzen Aufrufe durchwühlen, und nachsehen, mit
welchen URLs da hantiert wird und warum. Seltsam ist, dass das Problem
die DTD zu sein scheint... da sollte es doch nun wirklich egal sein, aus
welchem Stream das XML gelesen wird, zumal es laut Deiner Aussage ohne
den PMIS ja geht.
Bist Du *sicher*, dass Du sonst nichts verändert hast? Also so *richtig*
sicher? Hast Du nachgesehen? *g*
Unabhängig davon solltest Du auf jeden Fall einen BufferedInputStream um
den PMIS wickeln.
Gruß,
Michael
Also ich bin mir ganz sicher das ich nix geändert habe. Ich schreibe
wirklich nur die eine Zeile um. Es liegt aber auch nicht am PMI
sondern generell an den Streams. Ich bekomme diesen Fehler jedesmal
wenn ich versuche an den Parser einen Stream zu übergeben. Wenn ich
aber das File übergebe funktioniert es wunderbar. Hab auch schon ein
paar Stunden ausprobiert durch irgendwelche Schalter den Fehler
abzufangen. Aber das war nciht wirklich von Erfolg gekrönt.
Hab im Internet auch nur ein paar Einträge gefunden die auch das
Problem hatten. Aber irgendwie war nie eine Antwort dabei die dieses
Problem löst.
Werde mal weitersuchen und gucken ob ich was finde.
michael paap
2003-12-23 15:52:35 UTC
Permalink
Post by Dennis Engelbrecht
Ich bekomme diesen Fehler jedesmal
wenn ich versuche an den Parser einen Stream zu übergeben. Wenn ich
aber das File übergebe funktioniert es wunderbar. Hab auch schon ein
paar Stunden ausprobiert durch irgendwelche Schalter den Fehler
abzufangen. Aber das war nciht wirklich von Erfolg gekrönt.
Hab im Internet auch nur ein paar Einträge gefunden die auch das
Problem hatten. Aber irgendwie war nie eine Antwort dabei die dieses
Problem löst.
Werde mal weitersuchen und gucken ob ich was finde.
Nur mal interessehalber: Wie sieht denn die DTD-URL in Deinem XML-File aus?

Gruß,
Michael
--
Die Adresse im From existiert, wird aber nicht gelesen. Daher:
Sollte ausnahmsweise eine Mail-Antwort auf ein Posting vonnöten sein,
bitte folgende Adresse verwenden: newsreply@<Absender-Domain>.
Lesen Sie weiter auf narkive:
Loading...