XSLT1.0:CSV到XML-如何分而治之
在大量引用堆栈溢出答案后,我得到了以下XSL,它使用列标题作为每个适当单元格的节点名,将CSV转换为XMLXSLT1.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: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="' '" />
<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问题中看到了“分而治之”的提法,但我不知道如何将字符串一分为二
所以我的问题是:
在这种情况下,使用XSLT执行分而治之的操作并不简单。有一些方法可以优化XSLT处理,您可能希望尝试一种不同的处理器,这种处理器的工作方式不同,但是您的代码不容易改进,因为它实际上不进行任何XML处理。它在一个包含字符串的大型单元素节点上运行。实际上,您只使用XPath函数解析字符串,使用XSLT变量存储字符串。消除XSLT开销会更有效 你的选择包括:
-Xmx
选项)李>
但是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>