根据阈值将XML文件拆分为多个文件

时间:2010-12-13 21:12:53

标签: xslt

我需要根据预定值拆分以下XML文件,对于此示例,假设我想在创建的每个文件中将“Item”节点限制为三(3)。

这是一个示例输入XML文件:

<Items>
  <Item>
    <Title>Title 1</Title>
    <DueDate>01-02-2008</DueDate>
  </Item>
  <Item>
    <Title>Title 2</Title>
    <DueDate>01-02-2009</DueDate>
  </Item>
  <Item>
    <Title>Title 3</Title>
    <DueDate>01-02-2010</DueDate>
  </Item>
  <Item>
    <Title>Title 4</Title>
    <DueDate>01-02-2011</DueDate>
  </Item>
  <Item>
    <Title>Title 5</Title>
    <DueDate>01-02-2012</DueDate>
  </Item>
  <Item>
    <Title>Title 6</Title>
    <DueDate>01-02-2013</DueDate>
  </Item>
  <Item>
    <Title>Title 7</Title>
    <DueDate>01-02-2013</DueDate>
  </Item>
</Items>

基于阈值3的所需输出将是三个文件,其中两个包含3个“项目”,最后一个包含剩余的“项目”,这将是一个。

这是我的XSLT示例,它允许我为每个项目拆分它们,这会产生七个单独的文件,但是,我希望根据“Item”节点的某个限制来限制文件的大小每个文件。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xsl:output method="xml" indent="yes" name="xml" />

<xsl:template match="/">

 <xsl:for-each select="//Item">
  <xsl:variable name="nTitle" select="Title"/>
  <xsl:variable name="filename" select="concat('Items\',$nTitle,'-','.xml')" />
  <xsl:value-of select="$filename" />
   <xsl:result-document  href="{$filename}"  format="xml">
         <xsl:copy-of select="."/>
  </xsl:result-document>
 </xsl:for-each>

</xsl:template>
</xsl:stylesheet>

3 个答案:

答案 0 :(得分:6)

此样式表:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="pItemsNumber" select="3"/>
    <xsl:template match="Items">
        <xsl:for-each-group select="Item"
                            group-adjacent="(position()-1) idiv $pItemsNumber">
            <xsl:result-document  href="Items\{current-grouping-key()}.xml">
                <Items>
                    <xsl:copy-of select="current-group()"/>
                </Items>
            </xsl:result-document>
        </xsl:for-each-group>
    </xsl:template>
</xsl:stylesheet>

输出:

<?xml version="1.0" encoding="UTF-8"?>
<Items>
    <Item>
        <Title>Title 1</Title>
        <DueDate>01-02-2008</DueDate>
    </Item>
    <Item>
        <Title>Title 2</Title>
        <DueDate>01-02-2009</DueDate>
    </Item>
    <Item>
        <Title>Title 3</Title>
        <DueDate>01-02-2010</DueDate>
    </Item>
</Items>

<?xml version="1.0" encoding="UTF-8"?>
<Items>
    <Item>
        <Title>Title 4</Title>
        <DueDate>01-02-2011</DueDate>
    </Item>
    <Item>
        <Title>Title 5</Title>
        <DueDate>01-02-2012</DueDate>
    </Item>
    <Item>
        <Title>Title 6</Title>
        <DueDate>01-02-2013</DueDate>
    </Item>
</Items>

<?xml version="1.0" encoding="UTF-8"?>
<Items>
    <Item>
        <Title>Title 7</Title>
        <DueDate>01-02-2013</DueDate>
    </Item>
</Items>

编辑糟糕!

答案 1 :(得分:0)

此转化

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:param name="pSplitNum" select="3"/>

 <xsl:template match="node()|@*" name="identity">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="Item[position() mod $pSplitNum eq 1]">
  <xsl:result-document href=
   "file{position()}-{min((position()+$pSplitNum -1, count(/*/Item)))}.xml">
    <Items>
      <xsl:call-template name="identity"/>
      <xsl:apply-templates mode="copy" select=
      "following-sibling::Item[position() lt $pSplitNum]"/>
    </Items>
  </xsl:result-document>
 </xsl:template>
 <xsl:template match="/*"><xsl:apply-templates/></xsl:template>
 <xsl:template match="Item[position() mod $pSplitNum ne 1]"/>
</xsl:stylesheet>

应用于提供的XML文档

<Items>
  <Item>
    <Title>Title 1</Title>
    <DueDate>01-02-2008</DueDate>
  </Item>
  <Item>
    <Title>Title 2</Title>
    <DueDate>01-02-2009</DueDate>
  </Item>
  <Item>
    <Title>Title 3</Title>
    <DueDate>01-02-2010</DueDate>
  </Item>
  <Item>
    <Title>Title 4</Title>
    <DueDate>01-02-2011</DueDate>
  </Item>
  <Item>
    <Title>Title 5</Title>
    <DueDate>01-02-2012</DueDate>
  </Item>
  <Item>
    <Title>Title 6</Title>
    <DueDate>01-02-2013</DueDate>
  </Item>
  <Item>
    <Title>Title 7</Title>
    <DueDate>01-02-2013</DueDate>
  </Item>
</Items>

生成所需的三个xml文件

Saxon 9.1.0.5J from Saxonica
Java version 1.6.0_22
Stylesheet compilation time: 645 milliseconds
Processing file:/C:/Program%20Files/Java/jre6/bin/marrowtr.xml
Building tree for file:/C:/Program%20Files/Java/jre6/bin/marrowtr.xml using class net.sf.saxon.tinytree.TinyBuilder
Tree built in 10 milliseconds
Tree size: 38 nodes, 119 characters, 0 attributes
Loading net.sf.saxon.event.MessageEmitter
Writing to file:/C:/Program%20Files/Java/jre6/bin/file1-3.xml
Writing to file:/C:/Program%20Files/Java/jre6/bin/file4-6.xml
Writing to file:/C:/Program%20Files/Java/jre6/bin/file7-7.xml
Execution time: 101 milliseconds
Memory used: 11453088
NamePool contents: 20 entries in 20 chains. 6 prefixes, 7 URIs

请注意

  1. 这是身份规则模式的简单应用

  2. 每个Item开始一个新文件匹配,它会导致顶部元素的包装,处理自身和下一个$ pSplitNum -1(或者剩下的任何内容)最后一组),并将其输出为单个结果文档(文件)。

  3. 创建的每个文件的名称为:“filex-y.xml”,其中xy是{的起始和结束索引{1}}文件中写入的元素。

  4. 每个未启动新文件的Item都会被空匹配模板删除。这些元素以“复制”模式处理。

答案 2 :(得分:-1)

您可以实现在循环外声明的计数器。当计数器命中3时,重置它并设置新的文件名。否则,递增并附加到现有文件名。