Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将巨型XML文件拆分为n个子版本_Xml_Xslt_Sql Server Openxml - Fatal编程技术网

将巨型XML文件拆分为n个子版本

将巨型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> <

例如,giant文件有5000万行这样的内容:

<?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
    -源文档的名称
这是根据您的示例定制的XSLT-2.0模板(
split.XSLT
):


XSLT-2.0及以上版本非常适合此任务。
XSLT-3.0甚至支持流式处理

以下样式表使用将XML文件拆分为可配置数量的文件

它需要两个参数:

  • split
    -每个分割中的项目数
  • doc
    -源文档的名称
这是根据您的示例定制的XSLT-2.0模板(
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>