Search code examples
xmlxsltxslt-2.0xslt-3.0

Splitting XML into multiple files using XSLT 2.0


Using XSLT 2.0 I try to split xml and separate all item groups.

Original xml:

<Root Name="Root1">
  <Info Name="Info1" />
  <Group id="1">
    <Client Code="1">
      <ItemGroup Name="Group1"><Data/></ItemGroup>
      <ItemGroup Name="Group2"><Data/></ItemGroup>
    </Client>
    <Client Code="2">
      <ItemGroup Name="Group3"><Data/></ItemGroup>
      <ItemGroup Name="Group4"><Data/></ItemGroup>
    </Client>
  </Group>
</Root>

Desired output, part1:

<Root Name="Root1">
  <Info Name="Info1" />
  <Group id="1">
    <Client Code="1">
      <ItemGroup Name="Group1"><Data/></ItemGroup>
    </Client>
  </Group>
</Root>

Desired output, part2:

<Root Name="Root1">
  <Info Name="Info1" />
  <Group id="1">
    <Client Code="1">
      <ItemGroup Name="Group2"><Data/></ItemGroup>
    </Client>
  </Group>
</Root>
enter code here

Desired output, part3:

<Root Name="Root1">
  <Info Name="Info1" />
  <Group id="1">
    <Client Code="2">
      <ItemGroup Name="Group3"><Data/></ItemGroup>
    </Client>
  </Group>
</Root>

Desired output, part4:

<Root Name="Root1">
  <Info Name="Info1" />
  <Group id="1">
    <Client Code="2">
      <ItemGroup Name="Group4"><Data/></ItemGroup>
    </Client>
  </Group>
</Root>

I managed to split it, but having difficulties to add the parent nodes.

My best attempt:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/Root/Group/Client">
      <xsl:for-each-group select="ItemGroup" group-by="@Name">
        <xsl:result-document href="ItemGroup_{current-grouping-key()}.xml">
            <xsl:copy-of select="current-group()"/>
        </xsl:result-document>
      </xsl:for-each-group>
    </xsl:template> 
</xsl:stylesheet>

Can you point me in the right direction?


Solution

  • I think you want something like

    <xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      
      <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
      
      <xsl:template match="/">
        <xsl:for-each-group select="Root/Group/Client/ItemGroup" group-by="@Name">
          <xsl:result-document href="ItemGroup_{current-grouping-key()}.xml">
              <xsl:apply-templates select="/*"/>
          </xsl:result-document>
        </xsl:for-each-group>
      </xsl:template>
      
      <xsl:mode on-no-match="shallow-copy"/>
      
      <xsl:template match="Group | Client | ItemGroup">
        <xsl:if test=". intersect current-group()/ancestor-or-self::*">
          <xsl:next-match/>
        </xsl:if>
      </xsl:template>
        
    </xsl:stylesheet>
    

    Online example.