XML 文档转换 StackOverflowError
XML Document Transform StackOverflowError
我正在从头开始构建 XML 文档。我写了一个class把元素插入遍历到XML里面。就是这样:
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();
}
}
现在我可以调用 "new XMLParser("").add("A").up().add("B").toXML(); “生成包含 XML 代码的字符串。
这适用于较小的文档,但如果 xml 变大,我会在 transformer.transform(...) in toXML( ):
Exception in thread "main" java.lang.WhosebugError
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]
有没有人知道如何最小化堆栈开销?我不想 fiddle 使用 JVM 设置,因为我希望它在不同的计算机上也 运行...
提前感谢您的想法或解决方案!
编辑:
这是使用目录的 Java 文件对象调用的递归代码,该目录遍历内部文件夹以从目录
的内容构建 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();
}
}
}
xml 是 XMLParser 对象,我只是在构造函数中初始化它
XMLParser.set(String value)
以及您构建目录文档的方式存在问题:
XMLParser.set(String value)
附加一个文本节点并将当前节点设置为该文本节点。
鉴于 stepAhead
中的构建器代码,您将元素向下一层,文本节点向下一层,但您只向上一层。
xml.add("Name").set(temp.getName()).up();
当应用于充满文件的深层目录时,输出是一个令人难以置信的深层嵌套文档。 Transformer实现使用递归遍历文档然后发生Whosebug。
如果你把XMLParser.set(String value)
改成
public XMLParser set(String value){
currentNode.appendChild(doc.createTextNode(value));
return this;
}
一切正常,输出看起来不错。 (在打印简单目录的结果时,您应该已经看到了错误的输出!)
无论如何,XMLParser 是一个智能 class,消除了 DOM 操作的痛苦。也许它最好命名为 XMLBuilder。
虽然它可能有点复杂,但使用 XMLStreamWriter
。这将允许流式传输 无限大 XML 文件。
您将不得不生成自己的缩进逻辑,但是见鬼,实现这样的细节就是您拥有 XMLParser
class 的原因,对吧?顺便说一句,那真的应该命名为 XMLGenerator
或 XMLBuilder
,你不觉得吗?
为了展示如何使用 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>
我正在从头开始构建 XML 文档。我写了一个class把元素插入遍历到XML里面。就是这样:
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();
}
}
现在我可以调用 "new XMLParser("").add("A").up().add("B").toXML(); “生成包含 XML 代码的字符串。
这适用于较小的文档,但如果 xml 变大,我会在 transformer.transform(...) in toXML( ):
Exception in thread "main" java.lang.WhosebugError
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]
有没有人知道如何最小化堆栈开销?我不想 fiddle 使用 JVM 设置,因为我希望它在不同的计算机上也 运行...
提前感谢您的想法或解决方案!
编辑: 这是使用目录的 Java 文件对象调用的递归代码,该目录遍历内部文件夹以从目录
的内容构建 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();
}
}
}
xml 是 XMLParser 对象,我只是在构造函数中初始化它
XMLParser.set(String value)
以及您构建目录文档的方式存在问题:
XMLParser.set(String value)
附加一个文本节点并将当前节点设置为该文本节点。
鉴于 stepAhead
中的构建器代码,您将元素向下一层,文本节点向下一层,但您只向上一层。
xml.add("Name").set(temp.getName()).up();
当应用于充满文件的深层目录时,输出是一个令人难以置信的深层嵌套文档。 Transformer实现使用递归遍历文档然后发生Whosebug。
如果你把XMLParser.set(String value)
改成
public XMLParser set(String value){
currentNode.appendChild(doc.createTextNode(value));
return this;
}
一切正常,输出看起来不错。 (在打印简单目录的结果时,您应该已经看到了错误的输出!)
无论如何,XMLParser 是一个智能 class,消除了 DOM 操作的痛苦。也许它最好命名为 XMLBuilder。
虽然它可能有点复杂,但使用 XMLStreamWriter
。这将允许流式传输 无限大 XML 文件。
您将不得不生成自己的缩进逻辑,但是见鬼,实现这样的细节就是您拥有 XMLParser
class 的原因,对吧?顺便说一句,那真的应该命名为 XMLGenerator
或 XMLBuilder
,你不觉得吗?
为了展示如何使用 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>