-2

It is real scenario only I have changed the data. I have below parent child relationship xml. I am trying to convert the below xml using XSLT.I am able to trverse the parent data but not able to give the conditions for child node like if child reference change for any moment it should seperate the sample otherwise it should seperate by childs.

Input document

<Samples>
    <Sample>
        <a1>a1name</a1>
        <b1>b1desc</b1>
        <c1ref>101</c1ref>
        <childref>101</childref>
        <eno>test</eno>
        <ename>somename</ename>
    </Sample>
    <Sample>
        <a1>a1name</a1>
        <b1>b1desc</b1>
        <c1ref>101</c1ref>
        <childref>101</childref>
        <eno>test123</eno>
        <ename>someothername</ename>
    </Sample>
    <Sample>
        <a1>a1name1</a1>
        <b1>b1desc1</b1>
        <c1ref>102</c1ref>
        <childref>102</childref>
        <eno>test1234</eno>
        <ename>someothername1</ename>
    </Sample>
    <Sample>
        <a1>a1name</a1>
        <b1>b1desc</b1>
        <c1ref>101</c1ref>
        <childref>101</childref>
        <eno>test</eno>
        <ename>somename</ename>
    </Sample>
    <Sample>
        <a1>a1name1</a1>
        <b1>b1desc1</b1>
        <c1ref>103</c1ref>
        <childref>103</childref>
        <eno>test1234</eno>
        <ename>someothername1</ename>
    </Sample>
</Samples>

Something the OP hasn't explained. Possibly an expected output document

<Samples>
    <Sample>
        <a1>a1name</a1>
        <b1>b1desc</b1>
        <c1ref>101</c1ref>
        <childs>
            <childref>101</childref>
            <eno>test</eno>
            <ename>somename</ename>
        </childs>
        <childs>
            <childref>101</childref>
            <eno>test123</eno>
            <ename>someothername</ename>
        </childs>
    </Sample>
    <Sample>
        <a1>a1name1</a1>
        <b1>b1desc1</b1>
        <c1ref>102</c1ref>
        <childs>
            <childref>102</childref>
            <eno>test1234</eno>
            <ename>someothername1</ename>
        </childs>
    </Sample>
</Samples>

The below XSLT work but it again repeats the childref 101.

    <?xml version="1.0" encoding="UTF-8"?> 
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0">       
    <xsl:output indent="yes" method="xml"/>
    <xsl:template match="Samples">     
    <xsl:copy>         
    <!-- select the first Sample -->
    <xsl:apply-templates select="Sample[1]"/>
    </xsl:copy> </xsl:template>  
    <xsl:template match="Sample">
    <!-- the a1 attribute in Sample will act as the identifier 
    (check if it is the same      element) -->     
    <xsl:variable name="identifier" select="a1"/>
     <xsl:copy>         
      <xsl:apply-templates select="a1"/> 
        <xsl:apply-templates select="b1"/>
         <xsl:apply-templates select="c1ref"/>
         <xsl:element name="childs">
             <xsl:apply-templates select="childref"/>
             <xsl:apply-templates select="eno"/>
             <xsl:apply-templates select="ename"/>
         </xsl:element>         
         <!-- get childs of Sample with same identifier -->
         <xsl:apply-templates 
         select="following-sibling::Sample[a1=$identifier]"
         mode="SameElement"/>     
</xsl:copy>     
<!-- select the nex Samples with different identifier -->
<xsl:apply-templates select="following-sibling::Sample[a1!=$identifier][1]"/>      </xsl:template>
<xsl:template match="Sample" mode="SameElement">
     <!-- here only output the child elements -->
     <xsl:element name="childs">
         <xsl:apply-templates select="childref"/>
         <xsl:apply-templates select="eno"/>
         <xsl:apply-templates select="ename"/>
     </xsl:element> </xsl:template>
<xsl:template match="*|@*|text()"> 
    <xsl:copy>
         <xsl:apply-templates/>
     </xsl:copy> 
</xsl:template> 
</xsl:stylesheet>      

How can I write the xslt which will produce the above output?

Nimantha
  • 6,405
  • 6
  • 28
  • 69
SSdev
  • 1
  • 1
  • Hello SSdev, I am tempted to recommend a Muenchian Grouping (example http://stackoverflow.com/questions/1753485/muenchian-grouping-group-within-a-node-not-within-the-entire-document). Have you tried that yet? Best regards, Peter – Peter Sep 03 '12 at 08:35
  • The above XSLT which i used is almost correct except it repeats the child node again which already covered in tag. – SSdev Sep 03 '12 at 10:25
  • SSdev, you say "version=1.0" in your stylesheet and tag it as "xslt-2.0". My solution below is in 1.0. Please be more careful next time with these specifications since there is a big difference between XSLT 1.0 and 2.0 when it comes to grouping. – Peter Sep 03 '12 at 16:04
  • SSdev, Unless you edit the question and provide the exact wanted result, no reader, regardless of their psychic powers, would be able to guess it. Please. – Dimitre Novatchev Sep 03 '12 at 18:28
  • @Peter: The question WAS tagged xslt-1.0. It wasn't SSdev that removed that tag. – Flynn1179 Sep 04 '12 at 08:08
  • @Flynn1179, Thank you for the info. I thought I retag it as XSLT 1.0 because according to SSdev's answer to my solution (XSLT 1.0) it is working for him. Even though he didn't give me points.... – Peter Sep 04 '12 at 08:27

2 Answers2

1

To be honest I could not figure out the error in your XSLT. So I came up with my own version using the Hierarchical Grouping (described by Jeni Tennison). This is a XSLT 1.0 solution. If I use this input XML:

<?xml version="1.0" encoding="UTF-8"?>
<Samples>
<Sample>
    <a1>a1name</a1>
    <b1>b1desc</b1>
    <c1ref>101</c1ref>
    <childref>101</childref>
    <eno>test</eno>
    <ename>somename</ename>
</Sample>
<Sample>
    <a1>a1name</a1>
    <b1>b1desc</b1>
    <c1ref>101</c1ref>
    <childref>101</childref>
    <eno>test123</eno>
    <ename>someothername</ename>
</Sample>
<Sample>
    <a1>a1name1</a1>
    <b1>b1desc1</b1>
    <c1ref>102</c1ref>
    <childref>102</childref>
    <eno>test1234</eno>
    <ename>someothername1</ename>
</Sample>
<Sample>
    <a1>a1name</a1>
    <b1>b1desc</b1>
    <c1ref>101</c1ref>
    <childref>101</childref>
    <eno>test</eno>
    <ename>somename</ename>
</Sample>
<Sample>
    <a1>a1name1</a1>
    <b1>b1desc1</b1>
    <c1ref>103</c1ref>
    <childref>103</childref>
    <eno>test1234</eno>
    <ename>someothername1</ename>
</Sample>
</Samples>

and apply this XSLT:

<?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:key name="keyByc1ref" match="Sample" use="c1ref"/>

<xsl:template match="Samples">
    <xsl:variable name="uniqueSet" select="Sample[generate-id()=generate-id(key('keyByc1ref',c1ref)[1])]"/>
    <Samples>
        <xsl:apply-templates select="$uniqueSet" mode="group"/>
    </Samples>
</xsl:template>

<xsl:template match="Sample" mode="group">
    <Sample>
        <xsl:copy-of select="a1"/>
        <xsl:copy-of select="b1"/>
        <xsl:apply-templates select="key('keyByc1ref',c1ref)" mode="item"/>
    </Sample>
</xsl:template>

<xsl:template match="Sample" mode="item">
    <childs>
        <xsl:copy-of select="childref"/>
        <xsl:copy-of select="eno"/>
        <xsl:copy-of select="ename"/>
    </childs>
</xsl:template>

</xsl:stylesheet>

I get this XML Output. I think it looks good, I was not sure what output is expected:

<?xml version="1.0" encoding="UTF-8"?>
<Samples>
<Sample>
    <a1>a1name</a1>
    <b1>b1desc</b1>
    <childs>
        <childref>101</childref>
        <eno>test</eno>
        <ename>somename</ename>
    </childs>
    <childs>
        <childref>101</childref>
        <eno>test123</eno>
        <ename>someothername</ename>
    </childs>
    <childs>
        <childref>101</childref>
        <eno>test</eno>
        <ename>somename</ename>
    </childs>
</Sample>
<Sample>
    <a1>a1name1</a1>
    <b1>b1desc1</b1>
    <childs>
        <childref>102</childref>
        <eno>test1234</eno>
        <ename>someothername1</ename>
    </childs>
</Sample>
<Sample>
    <a1>a1name1</a1>
    <b1>b1desc1</b1>
    <childs>
        <childref>103</childref>
        <eno>test1234</eno>
        <ename>someothername1</ename>
    </childs>
</Sample>
</Samples>

With the key in the beginning you identify all unique item sets. For each identified group you run the "mode=group" template which copies a1 and b1 and calls the item-template that copies the other 3 elements into the child node.

Nimantha
  • 6,405
  • 6
  • 28
  • 69
Peter
  • 1,786
  • 4
  • 21
  • 40
0

This is a grouping problem, and can easily be solved using xsl:for-each-group.

However, I haven't managed to work out exactly what your grouping criteria are from your example, so I can't give you precise code.

Mads Hansen
  • 63,927
  • 12
  • 112
  • 147
Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • Thanks Michael. The grouping or sorting should work on c1ref. If you see the above xml c1ref and childref are same. so wherever they both are same in sample they should come in single Sample. Otherwise it should come in seperate Sample tag. – SSdev Sep 03 '12 at 10:28
  • Then you want `` – Michael Kay Sep 03 '12 at 13:20