关于xslt:根据属性值拆分XML文件

Split XML file according attribute's value

需要根据属性值拆分XML文件。是否可以使用XSLT-1.0?如果没有可能用1.0版本做到这一点,我将不胜感激任何更高版本的XSLT代码。

这是数字拆分属性的值(10、11、12等)。但是我想解决方案的原理对于数字和非数字序列可能是通用的。当系统找到split-attribute的第一个新(更改)值时,将生成新文件。

(可选问题)。这些操作可能有多少个XML文件?是否可以处理3gb文件? 30GB档案? RAM是否有任何系统要求来处理此类文件大小?

来源:

1
2
3
4
5
6
7
8
9
10
11
12
13
<objects>
  <obj attribute-1="value" attribute-2="value2" split-attribute="10"/>
  <obj attribute-1="value" attribute-2="value2" split-attribute="10"/>
  <obj attribute-1="value" attribute-2="value2" split-attribute="10"/>

  <obj attribute-1="value" attribute-2="value2" split-attribute="11"/>
  <obj attribute-1="value" attribute-2="value2" split-attribute="11"/>
  <obj attribute-1="value" attribute-2="value2" split-attribute="11"/>

  <obj attribute-1="value" attribute-2="value2" split-attribute="12"/>
  <obj attribute-1="value" attribute-2="value2" split-attribute="12"/>
  <obj attribute-1="value" attribute-2="value2" split-attribute="12"/>
</objects>

期望的输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<objects>
  <obj attribute-1="value" attribute-2="value2" split-attribute="10"/>
  <obj attribute-1="value" attribute-2="value2" split-attribute="10"/>
  <obj attribute-1="value" attribute-2="value2" split-attribute="10"/>
</objects>
<!--=========================== file-1.xml ======================-->


<objects>
  <obj attribute-1="value" attribute-2="value2" split-attribute="11"/>
  <obj attribute-1="value" attribute-2="value2" split-attribute="11"/>
  <obj attribute-1="value" attribute-2="value2" split-attribute="11"/>
</objects>
<!--=========================== file-2.xml ======================-->

<objects>
  <obj attribute-1="value" attribute-2="value2" split-attribute="12"/>
  <obj attribute-1="value" attribute-2="value2" split-attribute="12"/>
  <obj attribute-1="value" attribute-2="value2" split-attribute="12"/>
</objects>
<!--=========================== file-3.xml ======================-->

这可以使用XSLT-2.0及更高版本来完成。所需的xsl:result-document函数是在2.0版中引入的。

现在解决方案很简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="/objects">
    <xsl:for-each-group select="obj" group-by="@split-attribute">
      <xsl:result-document href="{concat('File-',position(),'.xml')}" indent="yes">
        <objects>
          <xsl:copy-of select="current-group()" />
        </objects>
      </xsl:result-document>
    </xsl:for-each-group>
  </xsl:template>

</xsl:stylesheet>

输出是所需的,由三个单独的文件组成。


您有一个不错的XSLT 2.0答案,尽管即使在我看来,使用group-adjacent仍然可以满足您的需要("当系统找到split-attribute的第一个新(更改)值时,将生成新文件");要使其与XSLT 3和流(以及支持该功能的处理器,如Saxon 9 EE)一起使用,可以使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:mode stremable="yes"/>

  <xsl:template match="/objects">
    <xsl:for-each-group select="obj" group-adjacent="@split-attribute">
      <xsl:result-document href="file-{position()}.xml" indent="yes">
        <objects>
          <xsl:copy-of select="current-group()" />
        </objects>
      </xsl:result-document>
    </xsl:for-each-group>
  </xsl:template>

</xsl:stylesheet>

这样,它甚至应该可以处理非常大的文件。