I need to split the following XML file based on a predetermined value, for this example, lets assume I want to limit the "Item" node to three (3) within each file created.
Here's a sample input XML file:
<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>
&开发者_如何学JAVAlt;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>
The desired output based on the threshold value of 3, would be three files, two of which contain 3 "Item", and the last one containing the remaining "items", which would be one.
Here's a sample of my XSLT which does allow me to split them for each item, which results into seven separate files, however, what I desire is to limit the size of the file based on a certain limit of "Item" node per file.
<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>
This stylesheet:
<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>
Output:
<?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>
Edit: Oops!
This transformation:
<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>
when applied on the provided XML document:
<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>
produces the wanted three xml files:
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
Do note:
This is a simple application of the identity rule pattern.
Every
Item
starting a new file is matched and it causes the wrapping in a top element, processing of itself and the next $pSplitNum -1 (or whatever remains in the last group), and outputting this as a single result-document (file).The name of every file created is: "filex-y.xml", where
x
andy
are the starting and ending indexes of theItem
elements written in the file.Every
Item
that isn't starting a new file is deleted by an empty matching template. Such elements are processed in "copy" mode.
You could implement a counter that is declared outside of your loop. When the counter hits 3, reset it and set a new filename. Otherwise, increment and append to the existing filename.
精彩评论