将巨型XML文件拆分为n个子版本
例如,giant文件有5000万行这样的内容:将巨型XML文件拆分为n个子版本,xml,xslt,sql-server-openxml,Xml,Xslt,Sql Server Openxml,例如,giant文件有5000万行这样的内容: <?xml version="1.0" encoding="UTF-8" standalone="no"?> <root> <activity> <deliv> <subitem1>text</subitem1> <subitem2>text</subitem2> </deliv> <
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
<activity>
<deliv>
<subitem1>text</subitem1>
<subitem2>text</subitem2>
</deliv>
<deliv>
<subitem1>text</subitem1>
<subitem2>text</subitem2>
</deliv>
<deliv>
<subitem1>text</subitem1>
<subitem2>text</subitem2>
</deliv>
</activity>
</root>
文本
文本
文本
文本
文本
文本
每个“子”文件都有相同的结构,但大约有500万行,或是原始文件的十分之一
这样做的原因是为了在不耗尽内存(SQLServer的OPENXML)的情况下,将这些数据导入到数据库中更易于管理
XSLT是这里的最佳选择吗?XSLT可以完成这项工作。我建议您使用XSLTv2.0处理器,以便使用xsl:result文档。然后,您需要一点逻辑来决定何时在文件之间分割。您可以基于deliver元素的position(),或者尝试使用xsl:for each group来创建发送到每个文件的组。XSLT可以完成这项工作。我建议您使用XSLTv2.0处理器,以便使用xsl:result文档。然后,您需要一点逻辑来决定何时在文件之间分割。您可以基于deliver元素的position(),或者尝试使用xsl:for each group创建发送到每个文件的组。XSLT-2.0及更高版本非常适合此任务。
XSLT-3.0甚至支持流式处理 以下样式表使用将XML文件拆分为可配置数量的文件 它需要两个参数:
-每个分割中的项目数split
-源文档的名称doc
split.XSLT
):
XSLT-2.0及以上版本非常适合此任务。
XSLT-3.0甚至支持流式处理 以下样式表使用将XML文件拆分为可配置数量的文件 它需要两个参数:
-每个分割中的项目数split
-源文档的名称doc
split.XSLT
):
Saxon 9.8的企业版(Saxon 9.8 EE)支持使用XSLT的子集以仅向前的方式读取XML文档,只使用存储当前访问的节点及其祖先所需的内存 使用这种方法,您可以为每个组编写类似于
的代码select=“activity/deliver”group innect=“(position()-1)idiv$size”
来进行位置分组,通过deliver
元素读取文件deliver
,并将它们收集到$size
的组中:
<?xml version="1.0" encoding="UTF-8"?>
<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:param name="size" as="xs:integer" select="1000"/>
<xsl:mode on-no-match="shallow-copy" streamable="yes"/>
<xsl:template match="root">
<xsl:for-each-group select="activity/deliv" group-adjacent="(position() - 1) idiv $size">
<xsl:result-document href="split-{format-number(current-grouping-key() + 1, '00000')}.xml" indent="yes">
<root>
<activity>
<xsl:copy-of select="current-group()"/>
</activity>
</root>
</xsl:result-document>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
将输入拆分为多个文件,每个文件都有$size
deliver
元素(如果剩下的$size
元素少于,则分别是最后一个deliver
元素)
使用Saxon EE需要获得商业许可证,但存在试用许可证。Saxon 9.8企业版(Saxon 9.8 EE)支持此功能,允许您使用XSLT子集以仅向前的方式读取XML文档,只使用存储当前访问的节点及其祖先所需的内存
使用这种方法,您可以为每个组编写类似于的代码select=“activity/deliver”group innect=“(position()-1)idiv$size”
来进行位置分组,通过deliver
元素读取文件deliver
,并将它们收集到$size
的组中:
<?xml version="1.0" encoding="UTF-8"?>
<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:param name="size" as="xs:integer" select="1000"/>
<xsl:mode on-no-match="shallow-copy" streamable="yes"/>
<xsl:template match="root">
<xsl:for-each-group select="activity/deliv" group-adjacent="(position() - 1) idiv $size">
<xsl:result-document href="split-{format-number(current-grouping-key() + 1, '00000')}.xml" indent="yes">
<root>
<activity>
<xsl:copy-of select="current-group()"/>
</activity>
</root>
</xsl:result-document>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
将输入拆分为多个文件,每个文件都有$size
deliver
元素(如果剩下的$size
元素少于,则分别是最后一个deliver
元素)
使用Saxon EE需要获得商业许可证,但存在试用许可证。谢谢@zx485,我是XSLT新手,所以这很有帮助。在我的3.6Gb文件上尝试了这一点,但内存不足,不幸的是:线程“main”java.lang中出现异常。OutOfMemoryError:java堆空间
这很不幸。我从未使用过XSLT-3.0流媒体,这将是您在本例中的首选。也许其他人可以提供帮助。Martin Honnen展示了如何使解决方案可流化。感谢@zx485,我是XSLT新手,所以这很有帮助。在我的3.6Gb文件上尝试了这一点,但不幸的是内存不足:线程“main”java.lang中出现异常。OutOfMemoryError:java堆空间
这很不幸。我从未使用过XSLT-3.0流媒体,这将是您在本例中的首选。也许其他人可以帮忙。Martin Honnen展示了如何使解决方案简化。
<?xml version="1.0" encoding="UTF-8"?>
<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:param name="size" as="xs:integer" select="1000"/>
<xsl:mode on-no-match="shallow-copy" streamable="yes"/>
<xsl:template match="root">
<xsl:for-each-group select="activity/deliv" group-adjacent="(position() - 1) idiv $size">
<xsl:result-document href="split-{format-number(current-grouping-key() + 1, '00000')}.xml" indent="yes">
<root>
<activity>
<xsl:copy-of select="current-group()"/>
</activity>
</root>
</xsl:result-document>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>