XSLT1.0:CSV到XML-如何分而治之

XSLT1.0:CSV到XML-如何分而治之,xml,performance,xslt,csv,divide-and-conquer,Xml,Performance,Xslt,Csv,Divide And Conquer,在大量引用堆栈溢出答案后,我得到了以下XSL,它使用列标题作为每个适当单元格的节点名,将CSV转换为XML <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" exclude-result-prefixes="xsl"> <xsl:output method="xml" encoding="utf-8" /> <xsl:variabl

在大量引用堆栈溢出答案后,我得到了以下XSL,它使用列标题作为每个适当单元格的节点名,将CSV转换为XML

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    exclude-result-prefixes="xsl">
    <xsl:output method="xml" encoding="utf-8" />

    <xsl:variable name="newline" select="'&#10;'" />
    <xsl:variable name="comma" select="','" />
    <xsl:variable name="csv" select="." />
    <xsl:variable name="fields" select="substring-before( concat( $csv, $newline ), $newline )" />

    <xsl:template match="/">
        <xsl:element name="EXCHANGE">
            <xsl:element name="DDM">
                <xsl:call-template name="write-row">
                    <xsl:with-param name="rows" select="substring-after( $csv, $newline)"/>
                </xsl:call-template>
            </xsl:element>
        </xsl:element>
    </xsl:template>

    <xsl:template name="write-row">
        <xsl:param name="rows"/>

        <xsl:variable name="this-row" select="substring-before( concat( $rows, $newline ), $newline )" />
        <xsl:variable name="remaining-rows" select="substring-after( $rows, $newline )" />

        <xsl:if test="string-length($this-row) > 1">
            <xsl:element name="DDMSRS">
                <xsl:call-template name="write-item">
                    <xsl:with-param name="columns" select="$fields"/>
                    <xsl:with-param name="row" select="$this-row" />
                </xsl:call-template>
            </xsl:element>
        </xsl:if>

        <xsl:if test="string-length( $remaining-rows ) > 0">
            <xsl:call-template name="write-row">
                <xsl:with-param name="rows" select="$remaining-rows" />
            </xsl:call-template>
        </xsl:if>
    </xsl:template>


    <xsl:template name="write-item">
        <xsl:param name="row"/>
        <xsl:param name="columns"/>

        <xsl:variable name="col" select="substring-before( concat( $columns, $comma ), $comma)" />
        <xsl:variable name="remaining-items" select="substring-after( $row, $comma )" />
        <xsl:variable name="remaining-columns" select="substring-after( $columns, $comma )" />

        <xsl:if test="$col != ''">
            <xsl:element name="{$col}">
                <xsl:value-of select="substring-before( concat( $row, $comma ), $comma)" /> 
            </xsl:element>
        </xsl:if>

        <xsl:if test="string-length( $remaining-items ) > 0">
            <xsl:call-template name="write-item">
                <xsl:with-param name="columns" select="$remaining-columns"/>
                <xsl:with-param name="row" select="$remaining-items" />
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

</xsl:stylesheet>

在csv上运行XSL,如下所示(换行符为行分隔符):


将返回以下xml:

<?xml version="1.0" encoding="utf-8"?>
<EXCHANGE>
    <DDM>
        <DDMSRS>
            <COL_HEAD1>123456789</COL_HEAD1>
            <COL_HEAD2>Peter</COL_HEAD2>
            <COL_HEAD3>My address</COL_HEAD3>
        </DDMSRS>
    </DDM>
</EXCHANGE>

123456789
彼得
我的地址
我现在遇到的问题是,当我想处理csv中的许多行(1000或更多)时,我的内存不足

我在其他stackoverflow问题中看到了“分而治之”的提法,但我不知道如何将字符串一分为二

所以我的问题是:

  • 在这个场景中,我如何执行分治
  • 有没有其他方法可以提高这个XSL的性能 是否使用XSLT1.0

  • 在这种情况下,使用XSLT执行分而治之的操作并不简单。有一些方法可以优化XSLT处理,您可能希望尝试一种不同的处理器,这种处理器的工作方式不同,但是您的代码不容易改进,因为它实际上不进行任何XML处理。它在一个包含字符串的大型单元素节点上运行。实际上,您只使用XPath函数解析字符串,使用XSLT变量存储字符串。消除XSLT开销会更有效

    你的选择包括:

  • 增加内存(使用
    -Xmx
    选项)
  • 将文件分成更小的部分(需要格式良好的XML),并在XSLT中分别处理每个部分
    但是XSLT不能帮助您选择第2个选项,因为要开始处理您的文件,需要将其全部加载到内存中。它无法加载部分文本并将其拆分,因为每个片段都必须是格式良好的XML。因为您只有一个节点,所以即使是SAX解析器也可能没有那么高效。最好使用一个高效的字符串解析器,在这里可以拆分CSV,然后将每个片段包装在XML标记中。

    为了运行xslt,您需要一个格式良好的XML文档,所以“拆分”听起来不是正确的做法。您是否仅限于使用XSLT1.0?您可以尝试其他旨在克服xslt内存限制的技术(如SAX)。您使用什么XSLT引擎?也许您可以尝试更高性能的方法。我仅限于XSLT1.0。当我说分割时,我指的是将csv一分为二,分别处理每个位,并重复分割过程。关键是XSL正在工作,我只需要改进XSLT1.0本机功能的性能space@Peter如果使用某个工具会造成伤害,请使用其他工具。不要在XSLT1.0中重复这一点,而是使用a)适当的CSV解析器作为中间步骤(首选),b)自定义XSLT扩展或c)类似的XSLT扩展可以为您进行标记化。在香草XSLT1.0中实现类似的东西是没有用的。既然您使用的是Java,为什么要限制自己使用XSLT1.0?这在XSLT2.0中会容易得多,XSLT2.0在Java世界中已经使用了大约十年。感谢您的回复。正如我在上文所指出的,选择2似乎是唯一可行的解决办法。
    <?xml version="1.0" encoding="utf-8"?>
    <EXCHANGE>
        <DDM>
            <DDMSRS>
                <COL_HEAD1>123456789</COL_HEAD1>
                <COL_HEAD2>Peter</COL_HEAD2>
                <COL_HEAD3>My address</COL_HEAD3>
            </DDMSRS>
        </DDM>
    </EXCHANGE>