G
Ghast
Gast
Hallo,
mein Ziel ist, XML-Dateien zu parsen und daraus neue, nach bestimmten Tags gefilterte XML-Dateien zu erzeugen. Die Dateien können recht groß werden, bisher haben wir eine mit 500 MB, die nur einen Bruchteil der Informationen enthält. Daher hab ich von DOM gleich abgesehen und einen SAX-Parser benutzt. Für das Verarbeiten einer 30-MB-Testdatei braucht das Programm auf meinem Rechner etwas mehr als zwei Minuten.
Eine Bremse ist mir bereits klar: In den meisten startElement()-Aufrufen wird über eine ArrayList iteriert, um zu ermitteln, ob der aktuelle Tag in die Ausgabe soll oder nicht. Die vorher durch Eingaben erzeugte ArrayList enthält die Tags, die gespeichert werden sollen und die for-Schleife bricht erst ab, wenn der aktuelle Tag in der Liste entdeckt wurde oder sie ganz durchgegangen ist.
--> Gibt es hier eine schnellere/bessere Alternative zur ArrayList? Ehrlich gesagt habe ich mich mit Collections und Iterables nicht groß beschäftigt. Die Liste wird dynamisch erstellt, ist aber beim Parsen im Prinzip fest - wäre es besser, sie einfach zu einem regulären Array umzuwandeln?
Das scheint jedoch nicht das einzige Problem zu sein. Kommentiere ich die Listeniteration aus und führe einfach nur einen einfachen Test auf Gleichheit mit einem Dummy-Tag durch, benötigt das Programm dennoch fast eine Minute, um das 30-MB-Dokument zu parsen und die mit dem Dummy identischen Tags rauszuschreiben.
Hier der Parser:
Verdächtig in Sachen Tempo finde ich noch den Stack, in dem die zu evaluierenden Tags landen ... aber ich weiß nicht genau, wie sich das eleganter lösen ließe. Der wird in characters(), startElement() und in endElement() abgefragt.
Gibt es irgendwelche auffällige Bremsen in dem Ding? Bisher musste ich zum Glück nie größere Dateien verarbeiten (XML oder sonstige). Aber daher hab ich mich dann auch nicht wirklich mit Performanz im Allgemeinen beschäftigt.
mein Ziel ist, XML-Dateien zu parsen und daraus neue, nach bestimmten Tags gefilterte XML-Dateien zu erzeugen. Die Dateien können recht groß werden, bisher haben wir eine mit 500 MB, die nur einen Bruchteil der Informationen enthält. Daher hab ich von DOM gleich abgesehen und einen SAX-Parser benutzt. Für das Verarbeiten einer 30-MB-Testdatei braucht das Programm auf meinem Rechner etwas mehr als zwei Minuten.
Eine Bremse ist mir bereits klar: In den meisten startElement()-Aufrufen wird über eine ArrayList iteriert, um zu ermitteln, ob der aktuelle Tag in die Ausgabe soll oder nicht. Die vorher durch Eingaben erzeugte ArrayList enthält die Tags, die gespeichert werden sollen und die for-Schleife bricht erst ab, wenn der aktuelle Tag in der Liste entdeckt wurde oder sie ganz durchgegangen ist.
--> Gibt es hier eine schnellere/bessere Alternative zur ArrayList? Ehrlich gesagt habe ich mich mit Collections und Iterables nicht groß beschäftigt. Die Liste wird dynamisch erstellt, ist aber beim Parsen im Prinzip fest - wäre es besser, sie einfach zu einem regulären Array umzuwandeln?
Das scheint jedoch nicht das einzige Problem zu sein. Kommentiere ich die Listeniteration aus und führe einfach nur einen einfachen Test auf Gleichheit mit einem Dummy-Tag durch, benötigt das Programm dennoch fast eine Minute, um das 30-MB-Dokument zu parsen und die mit dem Dummy identischen Tags rauszuschreiben.
Hier der Parser:
Java:
public class LexParser extends DefaultHandler {
private Stack <Tag> evaluateTag;
private int depth;
private boolean insideTag = false;
public ArrayList <Tag> selectedTags;
private StringBuffer xmltext;
private boolean header;
// ------------------------------------------------------------------------------
// Parser
// ------------------------------------------------------------------------------
public LexParser (File parsefile, ArrayList list) {
xmltext = new StringBuffer("");
depth = 0;
evaluateTag = new Stack ();
selectedTags = list;
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
// Ignore external DTD
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",false);
// Build and start parser
SAXParser saxParser = factory.newSAXParser();
saxParser.parse(parsefile,this);
}
catch (ParserConfigurationException e) {
System.out.println("Configuration error");
return;
}
catch (SAXException e) {
System.out.println("SAX error " + e.getMessage());
return;
}
catch (IOException e) {
System.out.println("IO Error " + e.getMessage());
return;
}
}
public void startDocument() {
}
public void endDocument() {
}
public void characters(char[] ch, int start, int length) {
// collect header-characters
if (header) {
String text = new String (ch, start, length).replaceAll("\n","").replaceAll("\t","");
if (!text.equals("")) {
xmltext.append(text);
}
}
else if ((!evaluateTag.empty()) && (evaluateTag.peek().getDepth() == depth-1)) {
String text = new String (ch, start, length).replaceAll("\n","").replaceAll("\t","");
if (!text.equals("")) {
xmltext.append(text);
}
else
for (int i = 1; i < depth; i++) xmltext.append("\t");
}
}
public void startElement(String uri,String localName,String qName,Attributes attributes) throws SAXException {
depth++;
// header: evaluate completely
if (qName.equals("teiHeader") || header) {
header = true;
xmltext.append("\n");
for (int i=1; i<depth; i++) xmltext.append("\t");
// output tags with their attributes
xmltext.append("<"+qName);
int attr = attributes.getLength();
for (int i=0; i<attr; i++) {
xmltext.append(" "+attributes.getQName(i)+"=\""+attributes.getValue(i)+"\"");
}
xmltext.append(">");
}
// first 4 layers (TEI, text, body, div): always evaluate
else if (depth<5) {
for (int i=1; i<depth; i++) xmltext.append("\t");
// output tags with their attributes
xmltext.append("<"+qName);
int attr = attributes.getLength();
for (int i=0; i<attr; i++) {
xmltext.append(" "+attributes.getQName(i)+"=\""+attributes.getValue(i)+"\"");
}
xmltext.append(">\n");
}
// inside an evaluated tag: evaluate that tag and its relevant subtags
else if ((!evaluateTag.empty()) && (evaluateTag.peek().getDepth() == depth-1) && (qName.equals("string")||qName.equals("numeric")||qName.equals("binary")||qName.equals("symbol")) ) {
insideTag = true;
xmltext.append("\n");
for (int i = 1; i < depth; i++) xmltext.append("\t");
// output tags with their attributes
xmltext.append("<"+qName);
int attr = attributes.getLength();
for (int i=0; i<attr; i++) {
xmltext.append(" "+attributes.getQName(i)+"=\""+attributes.getValue(i)+"\"");
}
xmltext.append(">");
}
// everything beneath first layer, not inside evaluated tag: evaluate according to user's choice
else {
Tag thistag = new Tag(qName,attributes.getValue(0),"",depth);
for (Tag t: selectedTags) {
if (t.equals(thistag)) {
xmltext.append("\n");
for (int i = 1; i < depth; i++)
xmltext.append("\t");
xmltext.append("<"+qName);
int attr = attributes.getLength();
for (int i=0; i<attr; i++) {
xmltext.append(" "+attributes.getQName(i)+"=\""+attributes.getValue(i)+"\"");
}
xmltext.append(">");
evaluateTag.push(thistag);
break; // don't look up rest of the list, if already matched
}
}
}
}
public void endElement(String uri,String localName,String qName) throws SAXException {
// close header
if (header) {
xmltext.append("\n");
for (int i=1; i<depth; i++) xmltext.append("\t");
xmltext.append("</"+qName+">");
if (qName.equals("teiHeader")) {
header = false;
xmltext.append("\n\n");
}
}
// close first layers
else if (depth<5) {
xmltext.append("\n");
for (int i=1; i<depth; i++) xmltext.append("\t");
xmltext.append("</"+qName+">");
}
// close selected tags
else {
if (!evaluateTag.empty()) {
Tag thistag = evaluateTag.peek();
if ((qName.equals(thistag.getTagName())) && (thistag.getDepth()==depth)) {
xmltext.append("\n");
for (int i = 1; i < depth; i++) xmltext.append("\t");
xmltext.append("</"+qName+">\n");
evaluateTag.pop();
}
if (insideTag) {
xmltext.append("</"+qName+">");
insideTag = false;
}
}
}
depth--;
}
}
Verdächtig in Sachen Tempo finde ich noch den Stack, in dem die zu evaluierenden Tags landen ... aber ich weiß nicht genau, wie sich das eleganter lösen ließe. Der wird in characters(), startElement() und in endElement() abgefragt.
Gibt es irgendwelche auffällige Bremsen in dem Ding? Bisher musste ich zum Glück nie größere Dateien verarbeiten (XML oder sonstige). Aber daher hab ich mich dann auch nicht wirklich mit Performanz im Allgemeinen beschäftigt.