有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java使用STaX将xml转换为另一个xml需要很多时间

我使用以下代码将一个大的xml流转换为另一个流:

 import java.io.ByteArrayInputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.io.Writer;
 import javax.xml.stream.XMLEventReader;
 import javax.xml.stream.XMLEventWriter;
 import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 import javax.xml.stream.events.XMLEvent;
 import javax.xml.transform.Result;
 import javax.xml.transform.Source;
 import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.stax.StAXResult;
 import javax.xml.transform.stax.StAXSource;

 public class TryMe 
 {
   public static void main (final String[] args)
   {
    XMLInputFactory inputFactory = null;
    XMLEventReader eventReaderXSL = null;
    XMLEventReader eventReaderXML = null;
    XMLOutputFactory outputFactory = null;
    XMLEventWriter eventWriter = null;
    Source XSL = null;
    Source XML = null;
    inputFactory = XMLInputFactory.newInstance();
    outputFactory = XMLOutputFactory.newInstance();
    inputFactory.setProperty("javax.xml.stream.isSupportingExternalEntities", Boolean.TRUE);
    inputFactory.setProperty("javax.xml.stream.isNamespaceAware", Boolean.TRUE);
    inputFactory.setProperty("javax.xml.stream.isReplacingEntityReferences", Boolean.TRUE);
    try
    {
        eventReaderXSL = inputFactory.createXMLEventReader("my_template",
                new InputStreamReader(TryMe.class.getResourceAsStream("my_template.xsl")));
        eventReaderXML = inputFactory.createXMLEventReader("big_one", new InputStreamReader(
                TryMe.class.getResourceAsStream("big_one.xml")));
    }
    catch (final javax.xml.stream.XMLStreamException e)
    {
        System.out.println(e.getMessage());
    }

    // get a TransformerFactory object
    final TransformerFactory transfFactory = TransformerFactory.newInstance();

    // define the Source object for the stylesheet
    try
    {
        XSL = new StAXSource(eventReaderXSL);
    }
    catch (final javax.xml.stream.XMLStreamException e)
    {
        System.out.println(e.getMessage());
    }
    Transformer tran2 = null;
    // get a Transformer object
    try
    {

        tran2 = transfFactory.newTransformer(XSL);
    }
    catch (final javax.xml.transform.TransformerConfigurationException e)
    {
        System.out.println(e.getMessage());
    }

    // define the Source object for the XML document
    try
    {
        XML = new StAXSource(eventReaderXML);
    }
    catch (final javax.xml.stream.XMLStreamException e)
    {
        System.out.println(e.getMessage());
    }

    // create an XMLEventWriter object
    try
    {

        eventWriter = outputFactory.createXMLEventWriter(new OutputStreamWriter(System.out));
    }
    catch (final javax.xml.stream.XMLStreamException e)
    {
        System.out.println(e.getMessage());
    }

    // define the Result object
    final Result XML_r = new StAXResult(eventWriter);

    // call the transform method
    try
    {

        tran2.transform(XML, XML_r);
    }
    catch (final javax.xml.transform.TransformerException e)
    {
        System.out.println(e.getMessage());
    }

    // clean up
    try
    {
        eventReaderXSL.close();
        eventReaderXML.close();
        eventWriter.close();
    }
    catch (final javax.xml.stream.XMLStreamException e)
    {
        System.out.println(e.getMessage());
    }
}

}

我的_模板如下所示:

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

<xsl:preserve-space elements="*"/>

<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>


<xsl:template match="@k8[parent::point]">
  <xsl:attribute name="k8">
    <xsl:value-of select="'xxxxxxxxxxxxxx'"/>
  </xsl:attribute>
</xsl:template>

</xsl:stylesheet>

xml是一个很长的列表

<data>
  <point .... k8="blablabla" ... ></point>
  <point .... k8="blablabla" ... ></point>
  <point .... k8="blablabla" ... ></point>
  ....
  <point .... k8="blablabla" ... ></point>
</data>

如果在处理输入流时使用标识转换器(使用TransfFactory.newTransformer()而不是transFactory(XSL)),则会生成输出。取而代之的是我的模板,没有办法。。转换器读取所有输入,然后开始产生输出(当然,在产生结果之前通常会出现大量内存不足的情况)

有什么想法吗??我吓坏了。。我无法理解我的代码/xslt中的错误

非常感谢


共 (6) 个答案

  1. # 1 楼答案

    尝试apache xsltc以获得更好的性能——它使用代码生成来简化转换

    XSLt转换看起来非常简单,输入格式也非常简单——当然,您可以进行StAX/SAX手动处理,并获得非常好的性能提升

  2. # 2 楼答案

    正如其他人所指出的,使用Stax不会改变XSLT的工作方式:它在开始任何工作之前先读取所有内容。 如果需要处理非常大的文件,那么就必须使用XSLT以外的东西

    然后是不同的选择:

  3. # 3 楼答案

    使用XSL进行的转换有多复杂?你能单独使用StAX进行同样的转换吗

    有了StAX,编写一个解析器来匹配特定节点,然后在输出流中插入、更改或删除节点是非常容易的。因此,不必使用XSL进行转换,您可以单独使用StAX。通过这种方式,您可以受益于API的流性质(不在内存中缓冲大型树),因此不会出现内存问题

    顺便说一句,最近对另一个问题的回答可能会对你有所帮助

  4. # 4 楼答案

    XSLT 1.0和2.0在完整XML的树数据模型上运行,因此XSLT 1.0和2.0处理器通常将完整的XML输入文档读入树中,并创建一个结果树,然后进行序列化。您似乎认为使用StAX会改变XSLT的行为,但我不认为是这样,XSLT处理器会构建树,因为样式表可能需要复杂的XPath导航器,比如前面的或前面的同级

    然而,在使用Java时,可以查看Saxon 9.3及其experimental XSLT 3.0 streaming support,这样在处理非常大的XML输入文档时,就不应该耗尽内存

    XSLT中不寻常的部分是<xsl:template match="@k8[parent::point]">,通常简单地写为<xsl:template match="point/@k8">,但您需要使用XSLT处理器测试这是否会改变性能

  5. # 5 楼答案

    使用XSLT可能不是最好的方法,因为其他人已经指出,您的解决方案要求处理器在输出之前将整个文档读入内存。您可能希望考虑使用SAX解析器在每个节点中顺序读取,执行所需的任何转换(如果需要的话,使用数据驱动映射)并写出转换后的数据。这避免了在内存中创建整个文档树的要求,并且可以显著加快处理速度,因为您不需要构建复杂的文档来写出

    问问自己输出格式是否简单稳定,然后重新考虑XSLT的使用。对于常规数据的大型数据集,您可能还希望考虑XML是否是传输信息的好文件格式。

  6. # 6 楼答案

    The transformer reads all the input and then starts to produce the output (with a large stream of course very often an out of memory comes before a result.

    Any Idea?

    如果你发现这项工作需要很长时间才能完成,那么你需要重新设计你的任务方法,以避免在开始处理输出文件之前读取整个输入文件。没有什么可以通过调整代码来让它神奇地更快——你需要解决算法的核心问题