XML Document Transform StackOverflowError

lukengda

Mitglied
Hallo zusammen, ich baue mir ein XML-Dokument mit einer Klasse, die für das einfügen und traversieren im Dokument zuständig ist. Die Klasse sieht folgendermaßen aus:

Java:
import java.io.StringWriter;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xembly.ImpossibleModificationException;

public class XMLParser {
   
    private Document doc;
    private Node currentNode;
   
    public XMLParser(String path) {

        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
           
            doc = builder.newDocument();
            currentNode = doc.createElement("Root");
            ((Element) currentNode).setAttribute("Path", path);
            doc.appendChild(currentNode);


        } catch (ParserConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
   
    public XMLParser add(String name){
        currentNode = currentNode.appendChild(doc.createElement(name));
       
        return this;
    }
   
    public XMLParser attr(String name, String value){
        ((Element) currentNode).setAttribute(name, value);
       
        return this;
    }
   
    public XMLParser set(String value){
        currentNode = currentNode.appendChild(doc.createTextNode(value));
       
        return this;
    }
   
    public XMLParser up(){
        currentNode = currentNode.getParentNode();
       
        return this;
    }
   
    public String toXML() throws ImpossibleModificationException{
        final Transformer transformer;
        try {
            transformer = TransformerFactory.newInstance().newTransformer();
        } catch (final TransformerConfigurationException ex) {
            throw new IllegalStateException(ex);
        }
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "3");
        final StringWriter writer = new StringWriter();
        try {
            transformer.transform(
                new DOMSource(doc),
                new StreamResult(writer)
            );
        } catch (final TransformerException ex) {
            throw new IllegalArgumentException(ex);
        }
        return writer.toString();
    }
   
   
}

Ich kann dann mit Aufrufen wie "new XMLParser("").add("A").up().add("B").toXML();" Ein XML String erstellen.

Mit kleinen Dokumenten geht das auch, aber wenn das XML-Dokument zu groß wird, dann bekomme ich im letzten Schritt bei transformer.transform(...) einen Stackoverflow:

Code:
Exception in thread "main" java.lang.StackOverflowError
    at com.sun.org.apache.xml.internal.serializer.ToStream.characters(Unknown Source)
    at com.sun.org.apache.xml.internal.serializer.ToUnknownStream.characters(Unknown Source)
    at com.sun.org.apache.xml.internal.serializer.ToUnknownStream.characters(Unknown Source)
    at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(Unknown Source)
    at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(Unknown Source)
    at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(Unknown Source)
    at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(Unknown Source)
    at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(Unknown Source)
    at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(Unknown Source)
    at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(Unknown Source)
    at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(Unknown Source)
    at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(Unknown Source)
    at com.sun.org.apache.xalan.internal.xsltc.trax.DOM2TO.parse(Unknown Source)
   ...[1000 Zeilen lang]

Hat jemand eine Idee für mich, wie ich - ohne die JVM umzuschrauben - das Prozedere Stack-freundlicher gestalten kann?
 

zendo

Neues Mitglied
In deinem Beispiel willst du dich mit "up" und "add" dynamisch durch den Baum bewegen. Das geht eben nur wenn der gesamte XML-Baum im Speicher gehalten wird.

Ein erster Test wäre, ob es mit größeren Stackspace geht (JVM Setting -Xss:2m oder mehr).
Unabhängig ob man das so nutzen kann hätte man dann andere Fehlerquellen (Classloader etc) ausgeschlossen.

Eine Idee wäre: die End-Datei zu stückeln. Wer z.B. 200 Seiten Report baut, kann ja 10 Seiten bauen, generieren, wegspeichern, dann die nächsten 10 Seiten und am Ende alle zusammenfügen. Je nach Dokumentenstruktur kann das einfach oder schwierig sein.

Eine weitere Möglichkeit wäre das manuelle herausschreiben mit einem XMLStreamWriter (Stichwort: Java StaX). Dieser Weg ist aber sehr technisch, da man vom erzeugten finalen DOM-Baum erst alle Tags durchgehen muss.

Code:
Document document = ...
document.appendChild(...)
document.appendChild(...)
...

// Wenn fertig, root Node holen

Element rootNode = document.getDocumentElement();

// Hier wird StaX genutzt
XMLOutputFactory outputFactory = XMLOutputFactory.newFactory();
XMLStreamWriter writer = outputFactory.createXMLStreamWriter(dateiName, encoding);

// Pseudocode!
// Hier einfach das ganze Dokument durchgehen und jedes Element
// systematisch rausschreiben, mit oder ohne Attribute etc.

for (Element childNode : rootNode.allNodes())
 { 
    writer.writeStartElement(childNode.getElementName());
    // When attribute dann schreiben 
    // writer.writeAttribute(name);
   ...
    writer.writeEndElement();
    writer.flush(); <- hier wird der Outputbuffer geleert und Speicher zurückgegeben!
}

writer.writeEndDocument();
writer.close();

Dies ist etwas technisch, sollte aber in kurzer Zeit zu einem Ergebnis führen, wenn man unbedingt die Freiheit braucht sich durch den XML-Baum bewegen zu müssen.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
S XML Document Parsen und Ausgeben mit Suchfunktion XML & JSON 21
B Wie kann man das ecncoding in einem vorhandenen Document-Objekt ändern? XML & JSON 2
M java.lang.RuntimeException: Failed to parse document XML & JSON 4
sylo DOM Document in XML Datei schreiben XML & JSON 5
sambalmueslie JAXB - Unmarshall ein XML-Document das aus zwei XSD Definitionen besteht XML & JSON 8
L invalide xml document parsen?! XML & JSON 2
G Nodes in Document kopieren, nur die Childs, die noch nicht existieren XML & JSON 7
K Document null bei builder.parse XML & JSON 2
B jdom document aus string erzeugen? XML & JSON 1
G document is invalid: no grammar found. XML & JSON 9
M Wie kann ich aus ein Document-Tree ein PDF generieren XML & JSON 2
G Ein DOM-Document dem Sax übergeben? XML & JSON 2
S org.jdom.document in String umwandeln. XML & JSON 2
P Aus einem Node ein Document erstellen XML & JSON 2
R XML Document als String XML & JSON 2
C Kompliziertes XML-Document, wie lese ich es ein? XML & JSON 4
N FileStream auf Document XML & JSON 22
M XPath Problem im Zusammenhang mit document() XML & JSON 2
B XML-Document mit Java erzeugen und zuruecksenden XML & JSON 1
W XML-Document auslesen XML & JSON 2
W XML Transform Bug Workaround XML & JSON 1
G mit Transformer.transform ein Element überschreiben XML & JSON 2
0x7F800000 jdom mit xml.transform inkompatibel, was soll ich nehmen? XML & JSON 2
D transformer.transform(source, result) -> ObjectOutput XML & JSON 6
A StackOverflowError in XMLEncoder? XML & JSON 2

Ähnliche Java Themen

Neue Themen


Oben