2015-08-27 64 views
1

我从头开始构建XML文档。我写了一个类来插入和遍历元素到XML中。这是它:XML文档转换StackOverflowError

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; 

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(){ 
     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(); 
    } 


} 

现在我可以像 “新XMLParser的(” “)调用添加(” A “)上()加(” B “)toxml用于();”。生成一个包含XML代码的字符串。

这toxml用于中(的伟大工程,对于较小的文件,但如果XML越来越大,我得到一个#1,错误在transformer.transform(...)):

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 lines in console buffer displayed] 

没有人有关于如何最小化堆栈开销的想法?我不想摆弄JVM设置,因为我希望它可以在不同的计算机上运行...

在此先感谢您的想法或解决方案!

编辑: 这里是被称为与横贯内的文件夹来创建XML树出来的目录

private void stepAhead(File f) throws IOException { 
    if(f.isDirectory()){ 
     File[] ergebnis = f.listFiles(); 
     ArrayList<File> dateien = new ArrayList<File>(); 
     for (File temp : ergebnis) { 
      if (temp.isDirectory()){ 
       //System.out.println("Checking Directory: " + temp.getCanonicalFile()); 
       xml.add("Dir").attr("Name", temp.getName()); 
       stepAhead(temp); 
       xml.up(); 
      } 
      else if(temp.isFile()){ 
       dateien.add(temp); 
      } 
      else{ 
       throw new RuntimeException("Keine Datei und kein Ordner"); 
      } 

     } 
     for(File temp : dateien){ 
      BasicFileAttributes attributes = Files.readAttributes(temp.toPath(), BasicFileAttributes.class); 

      xml.add("File"); 
      xml.add("Name").set(temp.getName()).up(); 
      xml.add("Size").set(""+attributes.size()).up(); 
      xml.add("DateCreated").set(formatFileTime(attributes.creationTime())).up(); 
      xml.add("DateLastModified").set(formatFileTime(attributes.lastModifiedTime())).up(); 
      xml.up(); 
     } 
    } 
} 

的内容的目录中的Java文件对象的递归码XMLXMLParser的对象,我只是initialze它在构造函数中

+0

出现StackOverflow通常意味着有一些错误在您的代码中,而不是在JVM配置中。你能发布触发错误的代码吗? – Raffaele

+0

在使用xml/dom Java解决方案进行封装前,我使用了外部库来构建xml,并且没有溢出。 我在想这是转换,因为如果我删除转换,我不会得到一个结果,但它正在完成没有错误 –

回答

2

没有与XMLParser.set(String value)以及如何建立d问题目录文件:

XMLParser.set(String value)附加文本节点并将当前节点设置为该文本节点。

stepAhead中给出您的构建器代码,您将为元素和文本节点的另一个级别向下移动一个级别,但只会向上移动一个级别。

xml.add("Name").set(temp.getName()).up(); 

当应用于充满文件的深层目录时,输出是一个令人难以置信的深层嵌套文档。 Transformer实现使用递归遍历文档,然后发生一个堆栈溢出。

如果更改XMLParser.set(String value)

public XMLParser set(String value){ 
    currentNode.appendChild(doc.createTextNode(value)); 
    return this; 
} 

一切工作正常,输出好看。 (当打印一个简单目录的结果时,你应该已经看到了拧出的输出!)

无论如何XMLParser是一个聪明的类,从DOM操作中解脱出来。也许最好命名为XMLBuilder。

+1

很好的'set'实现。提示OP:通过这种改变,'currentNode'总是一个'Element',所以重命名并重新输入为'private Element currentElement'。 – Andreas

+0

谢谢你,你是我今晚的英雄!该班正在工作并重新命名。 –

+0

@Andreas,appendChild()和getParentNode()仍然会返回一个Note,因此如果可能的话,我将不得不向另一个方向施放?! –

1

虽然它可能有点复杂,但可以使用XMLStreamWriter。这将允许流式传输无限大的 XML文件。

你将不得不生成自己的缩进逻辑,但是,实现这样的细节就是为什么你有一个XMLParser类,对吧?顺便说一句,这应该真的被命名为XMLGeneratorXMLBuilder,你不觉得吗?

要展示如何使用XMLStreamWriter,这里有一个小的代码(大部分)使用你的榜样(new XMLParser("").add("A").up().add("B").toXML()):

XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newFactory(); 
XMLStreamWriter xmlStreamWriter = xmlOutputFactory.createXMLStreamWriter(System.out); 
try { 
    xmlStreamWriter.writeStartDocument(); 
    xmlStreamWriter.writeCharacters("\n"); 

    // <Root> ... 
    xmlStreamWriter.writeStartElement("Root"); 
    xmlStreamWriter.writeAttribute("Path", "..."); 
    xmlStreamWriter.writeCharacters("\n"); 

     // <A x="abc">Hello World</A> 
     xmlStreamWriter.writeCharacters(" "); 
     xmlStreamWriter.writeStartElement("A"); 
     xmlStreamWriter.writeAttribute("x", "abc"); 
     xmlStreamWriter.writeCharacters("Hello World"); 
     xmlStreamWriter.writeEndElement(); // end of A 
     xmlStreamWriter.writeCharacters("\n"); 

     // <B></B> 
     xmlStreamWriter.writeCharacters(" "); 
     xmlStreamWriter.writeStartElement("B"); 
     xmlStreamWriter.writeEndElement(); // end of B 
     xmlStreamWriter.writeCharacters("\n"); 

     // <C/> 
     xmlStreamWriter.writeCharacters(" "); 
     xmlStreamWriter.writeEmptyElement("C"); 
     xmlStreamWriter.writeCharacters("\n"); 

    // </Root> 
    xmlStreamWriter.writeEndElement(); // end of Root 

    xmlStreamWriter.writeEndDocument(); 
} finally { 
    xmlStreamWriter.close(); 
} 

输出:

<?xml version="1.0" ?> 
<Root Path="..."> 
    <A x="abc">Hello World</A> 
    <B></B> 
    <C/> 
</Root> 
+0

感谢Andreas的解决方案,wero对我来说有正确的答案,但班级被重新命名,如果我将来需要它,我会提出你的想法 –