dinbo93
dinbo93

Reputation: 35

Need to split and distribute xslt nodes

Need to transform XML structure mentioned below using XSLT 2.0 or 3.0,

from

<RD>
    <RE>
        <BI>B00</BI>
        <BI>B01</BI>
        <BI>B02</BI>
        <BI>B03</BI>
        <CI>C01</CI>
        <D>D01</D>
    </RE>
    <RE>
        <BI>B04</BI>
        <BI>B05</BI>
        <CI>C02</CI>
        <D>D02</D>
    </RE>
</RD>

to this:

<RD>
    <RE>
        <BI>B00</BI>
        <CI>C01</CI>
        <D>D01</D>
    </RE>
    <RE>
        <BI>B01</BI>
        <CI>C01</CI>
        <D>D01</DI>
    </RE>
    <RE>
        <BI>B02</BI>
        <CI>C01</CI>
        <D>D01</D>
    </RE>
    <RE>
        <BI>B03</BI>
        <CI>C01</CI>
        <D>D01</D>
    </RE>
    <RE>
        <BI>B04</BI>
        <CI>C02</CI>
        <D>D02</D>
    </RE>
    <RE>
        <BI>B05</BI>
        <CI>C02</CI>
        <D>D02</D>
    </RE>
</RD>

Explanation: I need to achieve the distribution of XML nodes of (CI),(D) to each of (BI) tags in every iteration of (RE) tag

Upvotes: 1

Views: 61

Answers (3)

Martin Honnen
Martin Honnen

Reputation: 167696

You can treat it as a grouping problem:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all"
  expand-text="yes">

  <xsl:output method="xml" indent="yes"/>
  
  <xsl:template match="RD">
    <xsl:copy>
      <xsl:for-each-group select="RE" group-by="BI">
        <xsl:copy>
          <BI>{current-grouping-key()}</BI>
          <xsl:apply-templates select="*[not(self::BI)]"/>
        </xsl:copy>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

  <xsl:mode on-no-match="shallow-copy"/>

</xsl:stylesheet>

Upvotes: 1

Mads Hansen
Mads Hansen

Reputation: 66783

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output indent="yes"/>

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

    <xsl:template match="BI">
        <RE>
            <xsl:copy-of select="."/>
            <xsl:copy-of select="following-sibling::*[not(self::BI)]"/>
        </RE>
    </xsl:template>

</xsl:stylesheet>

Upvotes: 0

Sebastien
Sebastien

Reputation: 2714

This could also have been solved simply like this :

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

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

  <xsl:template match="RD">
    <xsl:copy>
      <xsl:apply-templates select="RE/BI"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="BI">
    <RE>
      <xsl:copy-of select="."/>
      <xsl:copy-of select="following-sibling::CI"/>
      <xsl:copy-of select="following-sibling::D"/>
    </RE>
  </xsl:template>
  
</xsl:stylesheet>

See it working here : https://xsltfiddle.liberty-development.net/gVK6D4y

Upvotes: 0

Related Questions