2
<Items>
    <array>
        <item name="A">
            <name>A</name>
            <indate>20141112</indate>
            <inno>2</inno>
            <status>1</status>
            <level>12</level>
            <size>.1</size>
            <text>item a text </text>
        </item>
        <item name="B">
            <name>B</name>
            <indate>20141012</indate>
            <inno>5</inno>
            <status>1</status>
            <level>13</level>
            <size>.5</size>
            <text>item b text </text>
        </item>
        <item name="C">
            <name>C</name>
            <indate>20140912</indate>
            <inno>6</inno>
            <status>1</status>
            <level>12</level>
            <size>.2</size>
            <text>item c text </text>
        </item>
        <item name="A">
            <name>A</name>
            <ondate>20140612</ondate>
            <onno>9</onno>
        </item>
        <item name="B">
            <name>B</name>
            <ondate>20140212</ondate>
            <inno>7</inno>
        </item>
        <item name="D">
            <name>D</name>
            <indate>20140712</indate>
            <inno>9</inno>
        </item>
        <item name="A">
            <name>A</name>
            <status>1</status>
            <level>12</level>
            <size>.1</size>
            <text>item a text </text>
        </item>
        <item name="B">
            <name>B</name>
            <status>1</status>
            <level>13</level>
            <size>.5</size>
            <text>item b text </text>
        </item>
        <item name="D">
            <name>D</name>
            <status>1</status>
            <level>13</level>
            <size>.9</size>
            <text>item d text </text>
        </item>
    </array>
</Items>

I have this xml and i need to group it to following output and add the inno and onno elements to give sumno. And check indate and ondate to give greater latedate. And give empty elements whenever inno/onno/indate/ondate are not present. And remove the duplicates. how to write this in muenchian method

output:

<Items>
    <array>
        <item name="A">
            <name>A</name>
            <indate>20141112</indate>
            <inno>2</inno>
            <ondate>20140612</ondate>
            <onno>9</onno>
            <latedate>20141112</latedate>
            <sumno>11</sumno>
            <status>1</status>
            <level>12</level>
            <size>.1</size>
            <text>item a text </text>
        </item>
        <item name="B">
            <name>B</name>
            <indate>20141012</indate>
            <inno>5</inno>
            <ondate>20140212</ondate>
            <onno>7</onno>
            <latedate>20141012</latedate>
            <sumno>12</sumno>
            <status>1</status>
            <level>13</level>
            <size>.5</size>
            <text>item b text </text>
        </item>
        <item name="C">
            <name>C</name>
            <indate>20140912</indate>
            <inno>6</inno>
            <ondate/>
            <onno/>
            <latedate>20140912</latedate>
            <sumno>6</sumno>
            <status>1</status>
            <level>12</level>
            <size>.2</size>
            <text>item c text </text>
        </item>
        <item name="D">
            <name>D</name>
            <indate/>
            <inno/>
            <ondate>20140712</ondate>
            <onno>7</onno>
            <latedate>20140712</latedate>
            <sumno>7</sumno>
            <status>1</status>
            <level>13</level>
            <size>.9</size>
            <text>item d text </text>
        </item>
    </array>
</Items>

I used this xsl to group but not able to add and remove duplicates

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

            <xsl:key name="items-by-id" match="item[@name]" use="name"/>
            <xsl:template match="@* | node()">
                        <xsl:copy>
                                    <xsl:apply-templates select="@* | node()"/>
                        </xsl:copy>
            </xsl:template>
            <xsl:template match="array">
                        <xsl:copy>
                                    <xsl:apply-templates select="item[@name][generate-id() = generate-id(key('items-by-id', name)[1])]" mode="group"/>
                        </xsl:copy>
            </xsl:template>
            <xsl:template match="item[@name]" mode="group">
                        <xsl:copy>
                                    <xsl:copy-of select="name"/>
                                    <xsl:apply-templates select="key('items-by-id', name)"/>
            </xsl:copy>
            </xsl:template>
            <xsl:template match="item[@name]">
                        <xsl:apply-templates select="node()[not(self::name)]"/>
            </xsl:template>
</xsl:stylesheet>
mnvbrtn
  • 558
  • 1
  • 8
  • 27

1 Answers1

1

I think your code does correctly group the item elements by their name child elements. You also seem to want to eliminate duplicate child elements, I am not sure whether you want to do that by element name only or by element name and element contents. If you want to do it by element name then you can define a second key <xsl:key name="duplicated-elements" match="item/*" use="concat(../name, '|', local-name())"/>.

As for adding empty elements, you will need to check whether they exist.

Here is a stylesheet with such checks and the second key:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="items-by-id" match="item[@name]" use="name"/>
  <xsl:key name="duplicated-elements" match="item/*" use="concat(../name, '|', local-name())"/>

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

  <xsl:template match="array">
    <xsl:copy>
      <xsl:apply-templates select="item[@name][generate-id() = generate-id(key('items-by-id', name)[1])]" mode="group"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="item[@name]" mode="group">
    <xsl:copy>
      <xsl:variable name="current-group" select="key('items-by-id', name)"/>
      <xsl:copy-of select="name"/>

      <xsl:choose>
        <xsl:when test="$current-group/indate">
          <xsl:apply-templates select="$current-group/indate"/>
        </xsl:when>
        <xsl:otherwise>
          <indate/>
        </xsl:otherwise>
      </xsl:choose>

      <xsl:choose>
        <xsl:when test="$current-group/inno">
          <xsl:apply-templates select="$current-group/inno"/>
        </xsl:when>
        <xsl:otherwise>
          <inno/>
        </xsl:otherwise>
      </xsl:choose>

      <xsl:choose>
        <xsl:when test="$current-group/ondate">
          <xsl:apply-templates select="$current-group/ondate"/>
        </xsl:when>
        <xsl:otherwise>
          <ondate/>
        </xsl:otherwise>
      </xsl:choose>

      <xsl:choose>
        <xsl:when test="$current-group/onno">
          <xsl:apply-templates select="$current-group/onno"/>
        </xsl:when>
        <xsl:otherwise>
          <onno/>
        </xsl:otherwise>
      </xsl:choose>

      <latedate>
        <xsl:choose>
          <xsl:when test="$current-group/indate > $current-group/ondate">
            <xsl:value-of select="$current-group/indate"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$current-group/ondate"/>
          </xsl:otherwise>
        </xsl:choose>
      </latedate>

      <sumno>
        <xsl:value-of select="sum($current-group/inno | $current-group/onno)"/>
      </sumno>

      <xsl:apply-templates select="key('items-by-id', name)/*[not(self::name | self::indate | self::inno | self::ondate | self::onno)][generate-id() = generate-id(key('duplicated-elements', concat(../name, '|', local-name()))[1])]"/>
  </xsl:copy>
</xsl:template>


</xsl:stylesheet>

There are some issues left like checking for not existing dates but I hope you can sort it out.

Martin Honnen
  • 160,499
  • 6
  • 90
  • 110