我想XML
使用XSLT
. 我做了:
TransformerFactory factory = TransformerFactory.newInstance();
InputStream is =
this.getClass().getResourceAsStream(getPathToXSLTFile());
Source xslt = new StreamSource(is);
Transformer transformer = factory.newTransformer(xslt);
Source text = new StreamSource(new File(getInputFileName()));
transformer.transform(text, new StreamResult(new File(getOutputFileName())));
哪个输入文件有关于10000000
行,我有错误:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at com.sun.org.apache.xml.internal.utils.FastStringBuffer.append(FastStringBuffer.java:682)
at com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2DTM.characters(SAX2DTM.java:2111)
at com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl.characters(SAXImpl.java:863)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.characters(AbstractSAXParser.java:546)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:455)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:841)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
at com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager.getDTM(XSLTCDTMManager.java:421)
at com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager.getDTM(XSLTCDTMManager.java:215)
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.getDOM(TransformerImpl.java:556)
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:739)
at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:351)
at ru.magnit.task.utils.AbstractXmlUtil.transformXML(AbstractXmlUtil.java:66)
at ru.magnit.task.EntryPoint.main(EntryPoint.java:72)
在这一行:
transformer.transform(text, new StreamResult(new File(getOutputFileName())));
这是什么原因,是否可以在没有堆大小的情况下以某种方式进行优化?
更新:我的XSLT
文件:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="entries">
<entries>
<xsl:apply-templates/>
</entries>
</xsl:template>
<xsl:template match="entry">
<entry>
<xsl:attribute name="field">
<xsl:apply-templates select="*"/>
</xsl:attribute>
</entry>
</xsl:template>
通常,XSLT 1.0 和 2.0 使用数据模型,该模型将完整的 XML 输入拉入树模型以允许完整的 XPath 导航,从而导致内存使用量随着输入文档的大小而增加。
因此,除非您在当前文档大小导致内存不足的情况下增加堆空间,否则您无能为力,至少在一般情况下,可能有特定于 XSLT 处理器和一些特定于 XSLT 的优化,具体取决于您的具体 XSLT 代码,但是您无法避免处理器首先拉入完整文档。我们需要查看您的 XSLT 以尝试判断它是否可以优化。分析样式表有助于确定要优化的区域,我不确定 Xalan 是否支持这一点。而且我不确定堆栈跟踪是否仅仅意味着 Xalan 在为您的大输入构建 DTM(它的树模型)时已经耗尽内存,在这种情况下,优化 XSLT 代码显然没有帮助,因为它甚至没有被执行.
您可以尝试的 Java 特定方法是使用https://docs.oracle.com/javase/8/docs/api/javax/xml/transform/sax/SAXTransformerFactory.html从样式表和链创建 SAX 过滤器它使用默认的 Transformer 来序列化过滤器的结果,我想我曾经尝试过,发现它比使用 Transformer 的传统方法消耗更少的内存。
XSLT 3.0 尝试使用新的流式传输方法 ( https://www.w3.org/TR/xslt-30/#streaming-concepts )解决内存问题,但是到目前为止,Saxon 9 EE 只有一种实现,一种商业产品。通常,样式表不一定是可流式传输的,相反,您必须重写它以使其可流式传输(如果可能的话,例如使用流式传输无法对输入节点进行排序)。
例如,您发布的样式表转换为 XSLT 3.0 以使用流式传输(无需重写,只需要将默认模式设置为可流式传输)是
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:mode streamable="yes"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="entries">
<entries>
<xsl:apply-templates/>
</entries>
</xsl:template>
<xsl:template match="entry">
<entry>
<xsl:attribute name="field">
<xsl:apply-templates select="*"/>
</xsl:attribute>
</entry>
</xsl:template>
</xsl:stylesheet>
Saxon 9.8 EE 和 Exselt 的测试版将其评估为可流式传输。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句