0
votes

I have an XML like following.

<Doc>
<row>
  <Col1>13820PKS-</Col1> 
  <Col6>01</Col6> 
  <Col9>1507462800</Col9> 
  <Col12>15074628</Col12> 
  <Col14>4</Col14> 
  </row>
<row>
  <Col1>13820PKS-</Col1> 
  <Col6>01</Col6> 
  <Col9>1507462800</Col9> 
  <Col12>15074629</Col12> 
  <Col14>5</Col14> 
  </row>
 <row>
  <Col1>13820PKS-</Col1> 
  <Col6>01</Col6> 
  <Col9>1808502801</Col9> 
  <Col12>18085021</Col12> 
  <Col14>1</Col14> 
  </row>
 <row>
  <Col1>13820PKS-</Col1> 
  <Col6>02</Col6> 
  <Col9>2710004100</Col9> 
  <Col12>2710004100</Col12> 
  <Col14>1</Col14> 
  </row>
</Doc>

The Document actually has more than 2000 rows. The end result should be

<Doc>
    <ListID id="01">
        <MainArt>
            <ItemCode>13820PKS-</ItemCode>
            <List>
                <SubArt>
                    <ItemCode>1507462800</ItemCode>
                    <SubArtList>
                        <row>
                            <ItemCode>15074628</ItemCode>
                            <Quantity>4</Quantity>
                        </row>
                        <row>
                            <ItemCode>15074629</ItemCode>
                            <Quantity>5</Quantity>
                        </row>
                    </SubArtList>
                </SubArt>
                <SubArt>
                    <ItemCode>1808502801</ItemCode>
                    <SubArtList>
                        <row>
                            <ItemCode>18085021</ItemCode>
                            <Quantity>1</Quantity>
                        </row>
                    </SubArtList>
                </SubArt>
            </List>
        </MainArt>
    </ListID>
    <ListID id="02">
        <MainArt>
            <ItemCode>13820PKS-</ItemCode>
            <List>
                <SubArt>
                    <ItemCode>2710004100</ItemCode>
                    <SubArtList>
                        <row>
                            <ItemCode>2710004100</ItemCode>
                            <Quantity>1</Quantity>
                        </row>
                    </SubArtList>
                </SubArt>
            </List>
        </MainArt>
    </ListID>
</Doc>

I am still in my learning Phase and don't really have the skills to use templates. I tried to do it with recursive for-each Loop but that also didn't work. Any Help will be greatly appreciated. Thanks

1
Are you trying to group the rows by Col6?Fung
In XSLT 1.0 you'll need to use a technique called Muenchian Grouping (jenitennison.com/xslt/grouping/muenchian.html) which may make your brain hurt the first time you see it, but is the best way! Could you possible amend your question to show the actual expected output for your given input, as it looks like you may need to do multiple grouping here. Thanks!Tim C
Thanks for your response. I know the Muenchian Grouping method (with Know means I read about it) but as you said it makes my brain hurt :).user2119031
I am still learning how to implement templates and I think without understanding the template implementation, I will not be able to understand the "Muenchian Grouping". I have to do multiple grouping. Col12 and Col14 comes under Col9 which comes under Col1 which comes under Col6. Its a bit complicated I know. The second part is the expected output.user2119031
The second part shows the structure of the expected output, but is not the actual output you are literally expecting, I believe? So, if you could show the actual output for your current input, that would help alot. Thanks!Tim C

1 Answers

0
votes

You are not making it easy in yourself with having three levels of multiple grouping! But here is what you do...

To start with, you are grouping by Col6 elements at the very top level, so you define a key to look up your row elements by their Col6 value.

<xsl:key name="Col6" match="row" use="Col6"/>

So, for a given value, the key will return all row elements where the Col6 element is equal to that value.

Now, to get the 'distinct' Col6 values, what happens is that you look at all row elements, but pick out only the ones which occur first in the group for the Col6 key. This is done like so,

<xsl:apply-templates 
     select="row[generate-id() = generate-id(key('Col6', Col6)[1])]" 
     mode="Col6" />

(Note the use of mode here, because the final XSLT will have multiple templates matching row elements, so you will need to distinguish between them).

Now, within the template that matches the row element for Col6, you then need to group by Col1 elements. This is where it gets slightly trickier, because you will need to define a key that is a combination of both Col6 and Col1 elements. (To allow for two Col1 elements that may have different Col6 values)

<xsl:key name="Col1" match="row" use="concat(Col6, '|', Col1)"/>

Note the use of the pipe | character to separate the values. This can be any character, just as long as it doesn't occur in either Col6 or Col1

Then to get the distinct Col1 elements within the current Col6, you would do this

<xsl:apply-templates 
     select="key('Col6', Col6)
             [generate-id() = generate-id(key('Col1', concat(Col6, '|', Col1))[1])]"
     mode="Col1" />

Finally, for your Col9 element, you would have a triply concatenated key.

<xsl:key name="Col9" match="row" use="concat(Col6, '|', Col1, '|', Col9)"/>

This could be used in a similar manner to get all the Col9 elements within the current Col1.

Putting this altogether, gives the following XSLT

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

  <xsl:key name="Col6" match="row" use="Col6"/>
  <xsl:key name="Col1" match="row" use="concat(Col6, '|', Col1)"/>
  <xsl:key name="Col9" match="row" use="concat(Col6, '|', Col1, '|', Col9)"/>

  <xsl:template match="/*">
    <xsl:copy>
      <xsl:apply-templates select="row[generate-id() = generate-id(key('Col6', Col6)[1])]" mode="Col6" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="row" mode="Col6">
    <ListID id="{Col6}">
      <xsl:apply-templates select="key('Col6', Col6)[generate-id() = generate-id(key('Col1', concat(Col6, '|', Col1))[1])]" mode="Col1" />
    </ListID>
  </xsl:template>

  <xsl:template match="row" mode="Col1">
    <MainArt>
      <ItemCode>
        <xsl:value-of select="Col1"/>
      </ItemCode>
      <List>
        <xsl:apply-templates select="key('Col1', concat(Col6, '|', Col1))[generate-id() = generate-id(key('Col9', concat(Col6, '|', Col1, '|', Col9))[1])]" mode="Col9" />
      </List>
    </MainArt>
  </xsl:template>

  <xsl:template match="row" mode="Col9">
    <SubArt>
      <ItemCode>
        <xsl:value-of select="Col9"/>
      </ItemCode>
      <SubArtList>
        <xsl:apply-templates select="key('Col9', concat(Col6, '|', Col1, '|', Col9))" mode="Col12" />
      </SubArtList>
    </SubArt>
  </xsl:template>

  <xsl:template match="row" mode="Col12">
    <row>
      <ItemCode>
        <xsl:value-of select="Col12"/>
      </ItemCode>
      <Quantity>
        <xsl:value-of select="Col14"/>
      </Quantity>
    </row>
  </xsl:template>
</xsl:stylesheet>

When applied to your sample XML, the following is output

<Doc>
  <ListID id="01">
    <MainArt>
      <ItemCode>13820PKS-</ItemCode>
      <List>
        <SubArt>
          <ItemCode>1507462800</ItemCode>
          <SubArtList>
            <row>
              <ItemCode>15074628</ItemCode>
              <Quantity>4</Quantity>
            </row>
            <row>
              <ItemCode>15074629</ItemCode>
              <Quantity>5</Quantity>
            </row>
          </SubArtList>
        </SubArt>
        <SubArt>
          <ItemCode>1808502801</ItemCode>
          <SubArtList>
            <row>
              <ItemCode>18085021</ItemCode>
              <Quantity>1</Quantity>
            </row>
          </SubArtList>
        </SubArt>
      </List>
    </MainArt>
  </ListID>
  <ListID id="02">
    <MainArt>
      <ItemCode>13820PKS-</ItemCode>
      <List>
        <SubArt>
          <ItemCode>2710004100</ItemCode>
          <SubArtList>
            <row>
              <ItemCode>2710004100</ItemCode>
              <Quantity>1</Quantity>
            </row>
          </SubArtList>
        </SubArt>
      </List>
    </MainArt>
  </ListID>
</Doc>