2

Question is similar to this , earlier question Which Dimitre has answered already. There is a slight modification in the response xml. However this time, we need one element to be taken from the repeating blocks. Not sure if we can use xsl key function here.

my input xml

<M>
   <a>
      <b>
         <c f="123">
            <key>Al</key>
            <e NO="678">
               <f>Y</f>
               <g>
                  <h>FTO</h>
               </g>
            </e>
         </c>
      </b>
   </a>
   <a>
      <b>
         <c f="123">
            <key>Al</key>
            <e NO="678">
               <f>Y</f>
               <g>
                  <h>FTO</h>
               </g>
            </e>
         </c>
      </b>
   </a>
   <a>
      <b>
         <c f="567">
            <key>Al</key>
            <e NO="678">
               <f>Y</f>
               <g>
                  <h>FTO</h>
               </g>
            </e>
         </c>
      </b>
   </a>
   <a>
      <b>
         <somethingelse/>
      </b>
   </a>
</M>

my desired output xml - notice that in addition to removing the duplicate, we need to take the key element from repeating blocks. It may or may not be the same.

<M>
   <a>
      <b>
         <c f="123">
            <key>Al</key>
            <key>Al</key>
            <e NO="678">
               <f>Y</f>
               <g>
                  <h>FTO</h>
               </g>
            </e>
         </c>
      </b>
   </a>
   <a>
      <b>
         <c f="567">
            <key>Al</key>
            <e NO="678">
               <f>Y</f>
               <g>
                  <h>FTO</h>
               </g>
            </e>
         </c>
      </b>
   </a>
   <a>
      <b>
         <somethingelse/>
      </b>
   </a>
</M>
Community
  • 1
  • 1
Suresh
  • 1,081
  • 4
  • 21
  • 44

1 Answers1

1

This transformation:

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

         <xsl:key name="kAByC-F" match="a" use="*/c/@f"/>

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

         <xsl:template match=
          "a[*/c
           and
             not(generate-id()
                =
                 generate-id(key('kAByC-F', */c/@f)[1])
                 )
            ]"/>

         <xsl:template match="a/b/c[@f]">
          <c f="{@f}">
            <xsl:apply-templates select="key('kAByC-F', @f)/b/c/key"/>
            <xsl:apply-templates select="*[not(self::key)]"/>
          </c>
         </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<M>
    <a>
        <b>
            <c f="123">
                <key>Al</key>
                <e NO="678">
                    <f>Y</f>
                    <g>
                        <h>FTO</h>
                    </g>
                </e>
            </c>
        </b>
    </a>
    <a>
        <b>
            <c f="123">
                <key>Al</key>
                <e NO="678">
                    <f>Y</f>
                    <g>
                        <h>FTO</h>
                    </g>
                </e>
            </c>
        </b>
    </a>
    <a>
        <b>
            <c f="567">
                <key>Al</key>
                <e NO="678">
                    <f>Y</f>
                    <g>
                        <h>FTO</h>
                    </g>
                </e>
            </c>
        </b>
    </a>
    <a>
        <b>
            <somethingelse/>
        </b>
    </a>
</M>

produces the wanted, correct result:

<M>
   <a>
      <b>
         <c f="123">
            <key>Al</key>
            <key>Al</key>
            <e NO="678">
               <f>Y</f>
               <g>
                  <h>FTO</h>
               </g>
            </e>
         </c>
      </b>
   </a>
   <a>
      <b>
         <c f="567">
            <key>Al</key>
            <e NO="678">
               <f>Y</f>
               <g>
                  <h>FTO</h>
               </g>
            </e>
         </c>
      </b>
   </a>
   <a>
      <b>
         <somethingelse/>
      </b>
   </a>
</M>

Explanation:

  1. The identity rule copies every node "as-is". It is overriden by two templates matching specific nodes.

  2. The first overriding template deletes all a elements that aren't the first a element as specified using a key (Muenchian grouping method).

  3. The second overriding template matches and processes the c grandchildren of the undeleted (by the first overriding template) a elements.

Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431