0

I'd like to split one XML file into multiple smalled files using XSLT. I read that this is possible using exsl:document. I've managed to sort-of get it to work except one minor issue — I can only seem to output one file. Here's my XML:

<People>
    <Person>
        <FirstName>John</FirstName>
        <LastName>Doe</LastName>
    </Person>
    <Person>
        <FirstName>Jack</FirstName>
        <LastName>White</LastName>
    </Person>
    <Person>
        <FirstName>Mark</FirstName>
        <LastName>Wall</LastName>
    </Person>
    <Person>
        <FirstName>John</FirstName>
        <LastName>Ding</LastName>
    </Person>
    <Person>
        <FirstName>Cyrus</FirstName>
        <LastName>Ding</LastName>
    </Person>
    <Person>
        <FirstName>Megan</FirstName>
        <LastName>Boing</LastName>
    </Person>
</People>

Here's my XSLT:

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exsl="http://exslt.org/common"
  extension-element-prefixes="exsl"
  exclude-result-prefixes="exsl"
  version="1.0">

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

  <xsl:template match="/">
    <xsl:for-each select="People/Person">
      <exsl:document href="{//FirstName}_{//LastName}.xml">
        <People>
          <xsl:copy-of select="."/>
        </People>
      </exsl:document>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Executing this using xsltproc data.xsl data.xml generates only one file called John_Doe.xml. I can't find any other files.

How can I split all the Person into the separate files?

Mridang Agarwalla
  • 43,201
  • 71
  • 221
  • 382

1 Answers1

2

Change

  <xsl:template match="/">
    <xsl:for-each select="People/Person">
      <exsl:document href="{//FirstName}_{//LastName}.xml">
        <People>
          <xsl:copy-of select="."/>
        </People>
      </exsl:document>
    </xsl:for-each>
  </xsl:template>

to

  <xsl:template match="/">
    <xsl:for-each select="People/Person">
      <exsl:document href="{FirstName}_{LastName}.xml">
        <People>
          <xsl:copy-of select="."/>
        </People>
      </exsl:document>
    </xsl:for-each>
  </xsl:template>
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • Martin, would you be able to explain why the `//` caused such a behaviour? – Mridang Agarwalla Oct 24 '12 at 10:01
  • 1
    Your code creates a result document for each `Person`, but each time with the same name so you ended up with one file being created several times. The reason is that `//FirstName` selects all `FileName` descendants of the root node and the attribute value template `{//FirstName}` takes the string value of the first selected node. The same for `{//LastName}`. Instead you want to select the `FirstName` and `LastName` relative to each `Person` being the context node inside of the `for-each` body. That's what the relative path expressions `FirstName` and `LastName` do. – Martin Honnen Oct 24 '12 at 10:40