当XML包含大量行时,Java + XSLT执行速度很慢

时间:2017-01-04 12:56:50

标签: java xml xslt xslt-2.0 saxon

应用程序正在编写XML结构,然后使用XSLT文件对其进行处理,从而生成适合客户端的转换XML(在内存中)。问题在于,虽然合成时间不到一秒钟(行数约为10 000),但转换大约需要30秒。

这是java方法:

StringWriter parsedOutStringWriter = new StringWriter();
StringWriter xmlStringWriter = new StringWriter();
File xsltFile = new File(xslFileProperties.getLocation() + xslFileForProcessing);

JAXBContext jaxbContext = JAXBContext.newInstance(Report.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
jaxbMarshaller.marshal(report, xmlStringWriter);

TransformerFactory transformerFactory = new net.sf.saxon.TransformerFactoryImpl();
Source xsltSource = new StreamSource(xsltFile);
Transformer transformer = transformerFactory.newTransformer(xsltSource);
transformer.setParameter("versionParam", "2.0");
transformer.setParameter("clientType", clientType);
transformer.setParameter("cardType", cardTypeValue);

Source source = new StreamSource(new StringReader(xmlStringWriter.getBuffer().toString()));
Result resultXmlWithFormat = new StreamResult(parsedOutStringWriter);
transformer.transform(source, resultXmlWithFormat);

这是由jaxbMarshaller编组Report.class的XML结构(通常有大约10000 <transaction>个元素:

   <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<report>
    <reportObject>
        <object>TEST</object>
        <objectValue>111111</objectValue>
    </reportObject>
    <reportContent>
        <reportInterval>
            <startDate>2014-07-01T00:00:00+03:00</startDate>
            <endDate>2016-09-30T23:59:59.999+03:00</endDate>
        </reportInterval>
        <client>
            <clientId>1111</clientId>
            <clientName>Some Client Name</clientName>
            <clientTown>-</clientTown>
            <clientAddress>-</clientAddress>
        </client>
        <transaction>
            <transactionId>1111111</transactionId>
            <transactionBatchId>2016091201111111</transactionBatchId>
            <transactionCode>1111111111111111</transactionCode>
            <transactionDate>2016-09-12T11:38:49+03:00</transactionDate>
            <transactionMain>111</transactionMain>
            <transactionAmount>199</transactionAmount>
            <transactionACode>      </transactionACode>
            <transactionBatch>111</transactionBatch>
            <transactionBatchDate>2016-09-12T11:40:27+03:00</transactionBatchDate>
            <transactionServiceFee>0</transactionServiceFee>
            <transactionType>1</transactionType>
            <transactionCType>AAAAA</transactionCType>
            <transactionCurrency>111</transactionCurrency>
            <transactionTerminal>11111111 111</transactionTerminal>
            <transactionTId>AA11111</transactionTId>
            <transactionClientId>111111</transactionClientId>
            <transactionClientName>SOME Client</transactionClientName>
            <transactionNetAmount>199</transactionNetAmount>
        </transaction>
    </reportContent>
</report>

这是转换XSLT文件:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:fo="http://www.w3.org/1999/XSL/Format"
                exclude-result-prefixes="fo">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <!--<xsl:strip-space elements="*"/>-->
    <xsl:decimal-format name="english" decimal-separator="." grouping-separator="," />
    <xsl:param name="clientType" />
    <xsl:param name="cType" />
    <xsl:param name="Interval" />

    <xsl:template match="/report">

        <report>
            <reportObject>
                <object>
                    <xsl:value-of select="reportObject/object"/>
                </object>
                <objectValue>
                    <xsl:value-of select="reportObject/objectValue" />
                </objectValue>
            </reportObject>
            <reportContent>
                <client>
                    <clientId>
                        <xsl:attribute name="type"><xsl:value-of select="$clientType"/></xsl:attribute>
                        <xsl:value-of select="reportContent/client/clientId"/>
                    </clientId>
                    <clientName>
                        <xsl:value-of select="reportContent/client/clientName" />
                    </clientName>
                    <clientTown>
                        <xsl:value-of select="reportContent/client/clientTown" />
                        <xsl:if test="reportContent/client/clientTown = ''">-</xsl:if>
                    </clientTown>
                    <clientAddress>
                        <xsl:value-of select="reportContent/client/clientAddress" />
                        <xsl:if test="reportContent/client/clientAddress = ''">-</xsl:if>
                    </clientAddress>
                </client>
                <reportInterval>
                    <startDate>
                        <xsl:value-of select="format-dateTime(reportContent/reportInterval/startDate, '[D01].[M01].[Y0001]')"/>
                    </startDate>
                    <endDate>
                        <xsl:value-of select="format-dateTime(reportContent/reportInterval/endDate, '[D01].[M01].[Y0001]')"/>
                    </endDate>
                </reportInterval>
                <cardTypes>
                    <cardType>
                        <xsl:value-of select="$cType"/>
                    </cardType>
                </cardTypes>
                <xsl:for-each-group select="reportContent/transaction" group-by="transactionBatchId">
                    <xsl:sort select="transactionClientName" />
                    <xsl:sort select="transactionBatchDate" />
                    <xsl:sort select="transactionBatch" />
                    <batch>
                        <batchDetails>
                            <batchId>
                                <xsl:value-of select="transactionBatchId"/>
                            </batchId>
                            <batchClientId>
                                <xsl:value-of select="transactionClientId"/>
                            </batchClientId>
                            <batchClientName>
                                <xsl:value-of select="transactionClientName"/>
                            </batchClientName>
                            <batchTransactionTerminal>
                                <xsl:value-of select="transactionTerminal"/>
                            </batchTransactionTerminal>
                            <batchNumber>
                                <xsl:value-of select="transactionBatch"/>
                            </batchNumber>
                            <batchDate>
                                <xsl:value-of select="format-dateTime(transactionBatchDate,'[D01].[M01].[Y0001]')"/>
                            </batchDate>
                        </batchDetails>
                        <transactionList>
                            <xsl:for-each select="current-group()">
                                <xsl:sort select="transactionDate" />
                                <transaction>
                                    <transactionBatchId>
                                        <xsl:value-of select="transactionBatchId"/>
                                    </transactionBatchId>
                                    <transactionCode>
                                        <xsl:value-of select="transactionCode"/>
                                    </transactionCode>
                                    <transactionDate>
                                        <xsl:value-of select="format-dateTime(transactionDate,'[D01].[M01].[Y0001] [H01]:[m01]:[s01]')" />
                                    </transactionDate>
                                    <transactionMain>
                                        <xsl:value-of select="transactionMain" />
                                        <xsl:if test="transactionMain = ''">-</xsl:if>
                                    </transactionMain>
                                    <transactionACode>
                                        <xsl:value-of select="transactionACode" />
                                        <xsl:if test="transactionACode = ''">-</xsl:if>
                                    </transactionACode>
                                    <transactionAmount>
                                        <xsl:value-of select="format-number(transactionAmount div 100, '#,##0.00', 'english')" />
                                    </transactionAmount>
                                    <transactionServiceFee>
                                        <xsl:value-of select="format-number(transactionServiceFee div 100, '#,##0.00', 'english')" />
                                    </transactionServiceFee>
                                    <transactionNetAmount>
                                        <xsl:value-of select="format-number(transactionNetAmount div 100, '#,##0.00', 'english')" />
                                    </transactionNetAmount >
                                    <transactionCurrency>
                                        <xsl:value-of select="transactionCurrency" />
                                        <xsl:if test="transactionCurrency = ''">-</xsl:if>
                                    </transactionCurrency>
                                    <transactionClientId>
                                        <xsl:value-of select="transactionClientId" />
                                    </transactionClientId>
                                    <transactionBatch>
                                        <xsl:value-of select="transactionBatch" />
                                    </transactionBatch>
                                    <transactionBatchDate>
                                        <xsl:value-of select="format-dateTime(transactionBatchDate,'[D01].[M01].[Y0001]')" />
                                    </transactionBatchDate>
                                    <transactionType>
                                        <xsl:value-of select="transactionType" />
                                    </transactionType>
                                    <transactionCType>
                                        <xsl:value-of select="transactionCType" />
                                    </transactionCType>
                                </transaction>
                            </xsl:for-each>
                        </transactionList>
                        <!-- batch total -->
                        <batchTotalItems>
                            <xsl:value-of select="count(current-group()/transactionAmount)"/>
                        </batchTotalItems>
                        <batchTotalAmount>
                            <xsl:value-of select="format-number(sum(current-group()/transactionAmount) div 100, '#,##0.00', 'english')"/>
                        </batchTotalAmount>
                        <batchTotalServiceFee>
                            <xsl:value-of select="format-number(sum(current-group()/transactionServiceFee) div 100, '#,##0.00', 'english')"/>
                        </batchTotalServiceFee>
                        <batchTotalNetAmount>
                            <xsl:value-of select="format-number(sum(current-group()/transactionNetAmount) div 100, '#,##0.00', 'english')"/>
                        </batchTotalNetAmount>
                    </batch>
                </xsl:for-each-group>
                <!-- overall total -->
                <totalItems>
                    <xsl:value-of select="count(/report/reportContent/transaction/transactionAmount)"/>
                </totalItems>
                <totalAmount>
                    <xsl:value-of select="format-number(sum(/report/reportContent/transaction/transactionAmount) div 100, '#,##0.00', 'english')"/>
                </totalAmount>
                <totalFee>
                    <xsl:value-of select="format-number(sum(/report/reportContent/transaction/transactionServiceFee) div 100, '#,##0.00', 'english')"/>
                </totalFee>
                <totalNetAmount>
                    <xsl:value-of select="format-number(sum(/report/reportContent/transaction/transactionNetAmount) div 100, '#,##0.00', 'english')"/>
                </totalNetAmount>
            </reportContent>
        </report>
    </xsl:template>
</xsl:stylesheet>

这就是转换后的XML的样子(通常有大约10000 <transaction>个元素和相当多的<batch>个元素:

<report>
   <reportObject>
      <object>TEST</object>
      <objectValue>111111</objectValue>
   </reportObject>
   <reportContent>
      <client>
         <clientId type="">111</clientId>
         <clientName>Client Name</clientName>
         <clientTown>-</clientTown>
         <clientAddress>-</clientAddress>
      </client>
      <reportInterval>
         <startDate>01.07.2014</startDate>
         <endDate>30.09.2016</endDate>
      </reportInterval>
      <cardTypes>
         <cardType/>
      </cardTypes>
      <batch>
         <batchDetails>
            <batchId>2016091201111111</batchId>
            <batchClientId>1111111</batchClientId>
            <batchClientName>Some Client Name</batchClientName>
            <batchTransactionTerminal>11111111A11</batchTransactionTerminal>
            <batchNumber>89</batchNumber>
            <batchDate>14.04.2016</batchDate>
         </batchDetails>
         <transactionList>
            <transaction>
               <transactionBatchId>2016091201111111</transactionBatchId>
               <transactionCode>1111111111111111</transactionCode>
               <transactionDate>12.09.2016 09:33:52</transactionDate>
               <transactionMain>111</transactionMain>
               <transactionACode></transactionACode>
               <transactionAmount>1.99</transactionAmount>
               <transactionServiceFee>0.00</transactionServiceFee>
               <transactionNetAmount>1.99</transactionNetAmount>
               <transactionCurrency>111</transactionCurrency>
               <transactionClientId>1111111</transactionClientId>
               <transactionBatch>111</transactionBatch>
               <transactionBatchDate>14.04.2016</transactionBatchDate>
               <transactionType>1</transactionType>
               <transactionCType>AAAAA</transactionCType>
            </transaction>
         </transactionList>
       </batch>
    <reportContent>
</report>

有什么方法可以明智地改善这种XSLT性能?或者问题可能在java代码中?注意:模板缓存已经过测试,并没有多大帮助。

0 个答案:

没有答案