0

another newcomer to xslt here. I have a problem similar to this one - Applying Muenchian grouping for a simple XML with XSLT - but complicated by an extra layer of nodes.

I have this XML...

<ALLDATA>
  <THIS>
    <ID>datum 1</ID>
    <DATA>datarecord1</DATA>
    <RELATIONSHIPS>
      <rel>
        <relid>rd1</relid>
        <reldata>something</reldata>
      </rel>
    </RELATIONSHIPS>
  </THIS>
  <THIS>
    <ID>datum 1</ID>
    <DATA>datarecord1</DATA>
    <RELATIONSHIPS>
      <rel>
        <relid>rd2</relid>
        <reldata>other</reldata>
      </rel>
    </RELATIONSHIPS>
  </THIS>
  <THIS>
    <ID>rd1</ID>
    <DATA>relrecord1</DATA>
    <RELATIONSHIPS/>
  </THIS>
  <THIS>
    <ID>rd2</ID>
    <DATA>relrecord2</DATA>
    <RELATIONSHIPS/>
  </THIS>
</ALLDATA>

... and would like to convert it to ...

<ALLDATA>
  <THIS>
    <ID>datum 1</ID>
    <DATA>datarecord1</DATA>
    <RELATIONSHIPS>
      <rel>
        <relid>rd1</relid>
        <reldata>something</reldata>
      </rel>
      <rel>
        <relid>rd2</relid>
        <reldata>other</reldata>
      </rel>
    </RELATIONSHIPS>
  </THIS>
  <THIS>
    <ID>rd1</ID>
    <DATA>relrecord1</DATA>
    <RELATIONSHIPS/>
  </THIS>
  <THIS>
    <ID>rd2</ID>
    <DATA>relrecord2</DATA>
    <RELATIONSHIPS/>
  </THIS>
</ALLDATA>

The xslt (1.0) I'm using is obviously way off base so was hoping someone with more knowledge (hi!) could help put me right :)

Here is the useless xslt...

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="krel" match="THIS" use="ID"/>

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

 <xsl:template match="appex_user/node">
  <xsl:copy>
    <xsl:apply-templates select="THIS[generate-id() = generate-id(key('krel', ID)[1])]" mode="group"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="THIS/RELATIONSHIPS" mode="group">
  <xsl:copy>
   <xsl:copy-of select="RELATIONSHIPS/rel"/>
   <xsl:apply-templates select="key('krel', ID)"/>
  </xsl:copy>
 </xsl:template>

</xsl:stylesheet>

Actually - I've tried all sorts of combinations to no avail.

Community
  • 1
  • 1
  • Well, `match="appex_user/node"` does not match any of the input you have posted. – Martin Honnen Feb 25 '16 at 17:42
  • To be safe, shouldn't *DATA* also be part of the key? Even if *ID* and *DATA* were supposed to be linked one-to-one, there might be a situation, where there are *THIS* elements with same *ID* value, but different *DATA* values. Then running the stylesheet with only *ID* on the key would take only one of those *DATA* elements and all others with different values would be lost. Just saying. – xjuice Feb 25 '16 at 18:05
  • Ach.. the appex_user bit was from the original - I adjusted my tags to make it look more generic instead of using the real tags. – rosensfole Feb 26 '16 at 18:04
  • Re. the DATA tag: yes you're right but in my case it's always the same. – rosensfole Feb 26 '16 at 18:05

1 Answers1

0

There are a few things wrong with your XSLT

Firstly you have a template matching "appex_user/node" which is not in your XML. You need to be matching the root element "ALLDATA" here.

Secondly, you use the "mode" attribute when selecting the distinct THIS elements. There's nothing wrong with that, but you don't have a template matching the THIS element that also uses mode. This means XSLT will use its default template which will not output the THIS element, but continue matching its children. I don't think you really need to use "mode" in this case.

Now, you do have a template matching RELATIONSHIPS using mode, which will get matched, but when you use the key, you use it with a value of "ID" which will look for an element named ID as a child of the current RELATIONSHIPS node. But ID is not a child. You should use the expression ..\ID to get the node that is a child of the parent.

Try this XSLT

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="krel" match="THIS" use="ID"/>

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

 <xsl:template match="ALLDATA">
  <xsl:copy>
    <xsl:apply-templates select="THIS[generate-id() = generate-id(key('krel', ID)[1])]" />
  </xsl:copy>
 </xsl:template>

 <xsl:template match="THIS/RELATIONSHIPS">
  <xsl:copy>
   <xsl:apply-templates select="key('krel', ../ID)/RELATIONSHIPS/rel"/>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>
Tim C
  • 70,053
  • 14
  • 74
  • 93