我们可以在Java中使用xslt transfrmation和SAX解析器吗?

时间:2017-06-30 07:56:15

标签: java xml csv xslt saxparser

我有一个xm文件,我使用XSLT transformation使用DOM解析它并将数据存储到csv中。

但是现在我想在SAX中这样做,因为xml文件非常大。

现在我的问题是我们可以使用SAX parser进行xslt转换并将数据存储到csv中吗?

我到处搜索,但我没有任何有用的信息。

这是我用DOM编写的java代码

import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Document;

class Xml2Csv {

    public static void main(String args[]) throws Exception {
    // Setting path for .xsl file
    File stylesheet = new File("style.xsl");

    // Setting path for Eurex xml feed file
    File xmlSource = new File("eurex_ref_data.xml");

    //Dom initialization and parse xml
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    Document document = builder.parse(xmlSource);

    // Transformation of parsed xml to csv
    StreamSource stylesource = new StreamSource(stylesheet);
    Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource);
    Source source = new DOMSource(document);
    //System.out.println(source.toString());
    System.out.println("Generating CSV File");
    Result outputTarget = new StreamResult(new File("AID.csv"));
    transformer.transform(source, outputTarget);
    System.out.println("File has been generated");
}
}

这是我的示例XSLT代码..

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" >

  <xsl:output method="text"/>

  <xsl:template match="/">
    <xsl:text>PriSetPx,TxnTm,ID,AltID,AltIDSrc</xsl:text>
    <xsl:text>&#xA;</xsl:text>
    <xsl:for-each select="FIXML/Batch/SecDef">
      <xsl:variable name="secDef" select="concat(@PriSetPx,',',@TxnTm)" />
      <xsl:for-each select="Instrmt/AID">
        <xsl:value-of select="concat($secDef, ',',../@ID,',',@AltID,',',@AltIDSrc,'&#xA;')"/>    
      </xsl:for-each>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

提前致谢!

1 个答案:

答案 0 :(得分:1)

SAXSource https://docs.oracle.com/javase/8/docs/api/javax/xml/transform/sax/SAXSource.htmlStreamSource https://docs.oracle.com/javase/8/docs/api/javax/xml/transform/stream/StreamSource.html因此您根本不需要使用DOM来使用XSLT和Java。但您必须了解XSLT 1.0和2.0在任何情况下都会将完整的XML输入首先解析为建模XSLT / XPath数据模型的树表示。因此,虽然XSLT 1.0或2.0处理器的本机树模型可能比DOM树消耗更少的内存,但它肯定会随着输入的大小而增长。

至于您当前的代码,为避免明确使用DOM,您只需使用StreamSource(或者如果您真的需要SAXSource)而不是DOMSource transformer.transform(source, outputTarget); 1}}。

所以请使用例如

File xmlSource = new File("eurex_ref_data.xml");
Source source = new StreamSource(xmlSource);

让XSLT处理器使用其原生树表示。

如果您想处理非常大的XML文档并遇到内存问题,那么您可能需要查看XSLT 3.0和streaming(目前Saxon 9 EE支持,http://saxonica.com/html/documentation/using-xsl/embedding/jaxp-transformation.html),例如您添加到问题中的样式表可以轻松编写为

<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="text"/>

    <xsl:template match="/">
        <xsl:text>PriSetPx,TxnTm,ID,AltID,AltIDSrc</xsl:text>
        <xsl:text>&#xA;</xsl:text>
        <xsl:apply-templates select="FIXML/Batch/SecDef/Instrmt/AID"/>
    </xsl:template>

    <xsl:template match="AID">
        <xsl:value-of select="ancestor::SecDef/@PriSetPx, ancestor::SecDef/@TxnTm, ../@ID, @AltID, @AltIDSrc" separator=","/>
        <xsl:text>&#10;</xsl:text>
    </xsl:template>

</xsl:stylesheet>

然后很容易与Saxon 9.7或9.8 EE(http://saxonica.com/download/download_page.xml)一起使用和流式传输来创建CSV而不需要消耗太多内存,因为XSLT和流式传输避免了首先构建完整输入的树而是通过XML只能一次转发,逐个节点地处理它。

如果您有非常大的输入文档(我不确定他们支持XSLT有多好,他们专注于XQuery),或者考虑使用像BaseX或ExistDB这样的XML数据库。