vas
vas

Reputation: 25

Generate Node XSLT based on unique value

Have the following input

<item>
    <list>
        <name>a</name>
        <vaue>a1</vaue>
    </list>
    <list>
        <name>b</name>
        <vaue>b5</vaue>
    </list>
    <list>
        <name>c</name>
        <vaue>c9</vaue>
    </list>
    <list>
        <name>d</name>
        <vaue>d66</vaue>
    </list>
    <type>1</type>
</item>
<item>
    <list>
        <name>a</name>
        <vaue>a1</vaue>
    </list>
    <list>
        <name>b</name>
        <vaue>b5</vaue>
    </list>
    <list>
        <name>c</name>
        <vaue>c9</vaue>
    </list>
    <list>
        <name>d</name>
        <vaue>d66</vaue>
    </list>
    <type>2</type>
</item>
<item>
    <list>
        <name>a</name>
        <vaue>a1</vaue>
    </list>
    <list>
        <name>b</name>
        <vaue>b5</vaue>
    </list>
    <list>
        <name>c</name>
        <vaue>c9</vaue>
    </list>
    <list>
        <name>d</name>
        <vaue>d66</vaue>
    </list>
    <type>1</type>
</item>
<item>
    <list>
        <name>a</name>
        <vaue>a1</vaue>
    </list>
    <list>
        <name>b</name>
        <vaue>b5</vaue>
    </list>
    <list>
        <name>c</name>
        <vaue>c9</vaue>
    </list>
    <list>
        <name>d</name>
        <vaue>d66</vaue>
    </list>
    <type>2</type>
</item>

Would now like to have the following output

<item>
    <list>
        <name>a</name>
        <vaue>a1</vaue>
    </list>
    <list>
        <name>b</name>
        <vaue>b5</vaue>
    </list>
    <list>
        <name>c</name>
        <vaue>c9</vaue>
    </list>
    <list>
        <name>d</name>
        <vaue>d66</vaue>
    </list>
    <type>1</type>
</item>
<item>
    <list>
        <name>a</name>
        <vaue>a1</vaue>
    </list>
    <list>
        <name>b</name>
        <vaue>b5</vaue>
    </list>
    <list>
        <name>c</name>
        <vaue>c9</vaue>
    </list>
    <list>
        <name>d</name>
        <vaue>d66</vaue>
    </list>
    <type>2</type>
</item>
<item>
    <list>
        <name>a</name>
        <vaue>a9</vaue>
    </list>
    <list>
        <name>b</name>
        <vaue>b5</vaue>
    </list>
    <list>
        <name>c</name>
        <vaue>c9</vaue>
    </list>
    <list>
        <name>d</name>
        <vaue>d66</vaue>
    </list>
    <type>1</type>
</item>
<item>
    <list>
        <name>a</name>
        <vaue>a1</vaue>
    </list>
    <list>
        <name>b</name>
        <vaue>b5</vaue>
    </list>
    <list>
        <name>c</name>
        <vaue>c9</vaue>
    </list>
    <list>
        <name>d</name>
        <vaue>d66</vaue>
    </list>
    <type>2</type>
</item>
<item>
    <list>
        <name>a</name>
        <vaue>a1</vaue>
    </list>
    <type>3</type>
</item>
<item>
    <list>
        <name>a</name>
        <vaue>a9</vaue>
    </list>
    <type>3</type>
</item>

For each item present with type as 1 would like to create a new item if there if the list contains a name which is "a" . However would like to avoid duplicates. Was able to achieve this output already with a two step process.. first to create items with duplicates and then a separate key match to remove the duplicates.

Is there a way we can achieve this in one step instead of to create duplicates and then filter duplicates

Upvotes: 0

Views: 36

Answers (1)

Alejandro
Alejandro

Reputation: 1882

This is just a grouping problem. This stylesheet:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:key name="item-by-vaue" match="item[type=1]" use="list[name='a']/vaue"/>

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

  <xsl:template match="root">
      <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
      <xsl:for-each 
        select="item[type=1]
                    [count(.|key('item-by-vaue',list[name='a']/vaue)[1])=1]">
        <item>
          <xsl:apply-templates select="list[name='a']"/>
          <type>3</type>
        </item>
      </xsl:for-each>
      </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Using your input sample it outputs:

<root>
   <item>
      <list>
         <name>a</name>
         <vaue>a1</vaue>
      </list>
      <list>
         <name>b</name>
         <vaue>b5</vaue>
      </list>
      <list>
         <name>c</name>
         <vaue>c9</vaue>
      </list>
      <list>
         <name>d</name>
         <vaue>d66</vaue>
      </list>
      <type>1</type>
   </item>
   <item>
      <list>
         <name>a</name>
         <vaue>a1</vaue>
      </list>
      <list>
         <name>b</name>
         <vaue>b5</vaue>
      </list>
      <list>
         <name>c</name>
         <vaue>c9</vaue>
      </list>
      <list>
         <name>d</name>
         <vaue>d66</vaue>
      </list>
      <type>2</type>
   </item>
   <item>
      <list>
         <name>a</name>
         <vaue>a1</vaue>
      </list>
      <list>
         <name>b</name>
         <vaue>b5</vaue>
      </list>
      <list>
         <name>c</name>
         <vaue>c9</vaue>
      </list>
      <list>
         <name>d</name>
         <vaue>d66</vaue>
      </list>
      <type>1</type>
   </item>
   <item>
      <list>
         <name>a</name>
         <vaue>a1</vaue>
      </list>
      <list>
         <name>b</name>
         <vaue>b5</vaue>
      </list>
      <list>
         <name>c</name>
         <vaue>c9</vaue>
      </list>
      <list>
         <name>d</name>
         <vaue>d66</vaue>
      </list>
      <type>2</type>
   </item>
   <item>
      <list>
         <name>a</name>
         <vaue>a1</vaue>
      </list>
      <type>3</type>
   </item>
</root>

Do note: your input sample doesn't match your expected output by the rules you've stated: there is no vaue element with 'a9' string value.

Upvotes: 1

Related Questions