tags:

views:

41

answers:

2

I'm having a hard time wrapping my head around XSLT but I heard it's possible to split an XML file into multiple files. Basically I'd like to copy all the elements up to the first file and after the last file and then add the individual file content for each output file.

Could someone give me some pointers on this if it's even possible?

Thanks,

complete.xml

<rootelem>
  <elem>
    <file attr1='1'>
      <content>content file 1</content>
    </file>
    <file attr2='2'>
      <content>content file 2</content>
    </file>
    <file attr3='3'>
      <content>content file 3</content>
    </file>
  </elem>
</rootelem>

OUTPUT:

complete_PART1.xml

<rootelem>
  <elem>
     <file attr1='1'>
        <content>content file 1</content>
     </file>
  </elem>
</rootelem>

complete_PART2.xml

<rootelem>
  <elem>
    <file attr2='2'>
      <content>content file 2</content>
    </file>
  </elem>
</rootelem>

complete_PART3.xml

<rootelem>
  <elem>
     <file attr3='3'>
        <content>content file 3</content>
     </file>
  </elem>
</rootelem>
+1  A: 

It is not possible in pure XSLT 1.0 to produce more than one output files. One could use the <exslt:document> extension element for this purpose.

In XSLT 2.0 use the <xsl:result-document> element.

Dimitre Novatchev
Hi Dimitre, thanks for your reply. I'm using xsl:result-document now and it splits the file but puts <file> as the top level element. However, I want to keep <root> and <elem> in each of the generated files. Any suggestions on that? <xsl:template match="/"> <xsl:for-each select="elem/file"> <xsl:result-document method="xml" href="file_{@id}-output.xml"> <xsl:copy-of select="."/> </xsl:result-document> </xsl:for-each> </xsl:template>
Nisse
+2  A: 

Responding to your comment on @Dimitre's answer...

You wrote,

<xsl:template match="/">
  <xsl:for-each select="elem/file">
    <xsl:result-document method="xml" href="file_{@id}-output.xml">
      <xsl:copy-of select="."/>
    </xsl:result-document>
  </xsl:for-each>
</xsl:template> 

This doesn't quite match your XML, which has rootelem as an outermost element, and your comment says root as an outermost element. You probably want something like this:

<xsl:template match="/root">
  <xsl:for-each select="elem/file">
    <xsl:result-document method="xml" href="file_{@id}-output.xml">
      <root>
        <xsl:copy-of select="/root/@*" />
        <elem>
          <xsl:copy-of select="../@* | ." />
        </elem>
      </root>
    </xsl:result-document>
  </xsl:for-each>
</xsl:template> 

You could get fancier, trying to use <xsl:copy> instead of literal result elements for root and elem, but it doesn't seem worth the effort unless they're going to vary.

LarsH
You're right Lars, sorry sloppy copying from the actual file. I did something similar to what you have but the problem is that root and elem have various attributes that i need to maintain. But maybe I can somehow use the parent <xsl:copy-of select=".."> still trying to wrap my head around xslt.
Nisse
@Nisse, I edited the answer to preserve the attributes of root and elem. The trouble with xsl:copy-of is that you can't modify the parts of what gets copied... you just copy the whole tree(s) under the node(s) you select. You can't add or omit anything. So you can't xsl:copy-of /root or /root/elem. But if you xsl:copy-of the needed attributes you're in good shape.
LarsH