Search code examples
xmlxsltxslt-1.0xslt-grouping

XSLT 1.0 loop elements after grouping


I need your help with a XSLT 1.0 problem.

Original XML:

    <businessevent>
       <catalog>
          <de name="16R">FIN</de>
          <ds name="35B">
             <de name="instrument_identification">ISIN AT0000A0U3T4</de>
             <de name="instrument_type">ISIN</de>
             <de name="instrument_code">AT0000A0U3T4</de>
             <de name="instrument_code_code">AT0000A0U3T4</de>
             <de name="instrument_code_umi_id">ATG2022113.4</de>
             <de name="instrument_code_code">AT0000A0U3T4</de>
             <de name="instrument_code_umi_id">ATG2022113.4_SG</de>
          </ds>
          <de name="16R">FIA</de>
          <de name="12A">:CLAS/ISIT/GOVT</de>
          <ds name="98A">
             <de name="date_type">MATU</de>
             <de name="date">20051122</de>
          </ds>
          <ds name="98A">
             <de name="date_type">ISSU</de>
             <de name="date">20060126</de>
          </ds>
          <de name="92A">:INTR//3,4</de>
          <de name="16S">FIA</de>
          <de name="90A">:MRKT//PRCT/114,16</de>
          <ds name="93B">
             <de name="amount_type">AGGR</de>
             <de name="unit_type">FAMT</de>
             <de name="amount">100</de>
          </ds>
          <ds name="93B">
             <de name="amount_type">AVAI</de>
             <de name="unit_type">FAMT</de>
             <de name="amount">100</de>
          </ds>
          <ds name="93B">
             <de name="amount_type">NAVL</de>
             <de name="unit_type">FAMT</de>
             <de name="amount">0</de>
          </ds>
          <de name="16R">SUBBAL</de>
          <ds name="93B">
             <de name="amount_type">AGGR</de>
             <de name="unit_type">FAMT</de>
             <de name="amount">100</de>
          </ds>
          <de name="16S">SUBBAL</de>
          <de name="19A">:HOLD//EUR6000,</de>
          <de name="16S">FIN</de>


          <de name="16R">FIN</de>
          <ds name="35B">
             <de name="instrument_identification">ISIN AT0000A0VRF9</de>
             <de name="instrument_type">ISIN</de>
             <de name="instrument_code">AT0000A0VRF9</de>
             <de name="instrument_code_code">AT0000A0VRF9</de>
             <de name="instrument_code_umi_id">ATG2019061.95</de>
          </ds>
          <de name="16R">FIA</de>
          <de name="12A">:CLAS/ISIT/GOVT</de>
          <ds name="98A">
             <de name="date_type">MATU</de>
             <de name="date">20120618</de>
          </ds>
          <ds name="98A">
             <de name="date_type">ISSU</de>
             <de name="date">20110703</de>
          </ds>
          <de name="92A">:INTR//1,95</de>
          <de name="16S">FIA</de>
          <de name="90A">:MRKT//PRCT/100,47</de>
          <ds name="93B">
             <de name="amount_type">AGGR</de>
             <de name="unit_type">FAMT</de>
             <de name="amount">200</de>
          </ds>
          <ds name="93B">
             <de name="amount_type">AVAI</de>
             <de name="unit_type">FAMT</de>
             <de name="amount">200</de>
          </ds>
          <ds name="93B">
             <de name="amount_type">NAVL</de>
             <de name="unit_type">FAMT</de>
             <de name="amount">0</de>
          </ds>
          <de name="16R">SUBBAL</de>
          <ds name="93B">
             <de name="amount_type">AGGR</de>
             <de name="unit_type">FAMT</de>
             <de name="amount">200</de>
          </ds>
          <de name="16S">SUBBAL</de>
          <de name="19A">:HOLD//EUR1000,</de>
          <de name="16S">FIN</de>
       </catalog>
    </businessevent>

As you can see it is a flat XML with a weird structure and I can only use XSLT 1.0 to manipulate it. The sub-structure repeats initiating with

    <de name="16R">FIN</de>

and ends with

    <de name="16S">FIN</de>

For each of this repeating structure I need to get some of the info and only the first occurrence of 93B with amount_type = AGGR. In the first "group" it repeats and its giving me problems.

Expected result:

    <businessevent>
       <catalog>
            <ds>
                <de name="instrument_identification">ISIN AT0000A0U3T4</de>
                <de name="instrument_type">ISIN</de>
                <de name="instrument_code">AT0000A0U3T4</de>
                <de name="amount">100</de>
            </ds>
        </catalog>
    </businessevent>

Thank you very much!


Solution

  • Based on your previous question, you can still do a form of "group-starting-with" by using the following key:

    <xsl:key name="start" match="catalog/*" use="generate-id(preceding-sibling::de[@name='16R'][. = 'FIN'][1])" />
    

    To get the first three elements you want, in "35B", you would then do this...

    <xsl:apply-templates select="key('start', generate-id())[self::ds[@name='35B']]" mode="ds-35B" />
    

    And do get the first "93B" element, with amount_type of "AGGR" you could do this:

    <xsl:apply-templates select="key('start', generate-id())[self::ds[@name='93B'][de[@name='amount_type']='AGGR']][1]" mode="ds-93B" />
    

    Try it this way...

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    
      <xsl:key name="start" match="catalog/*" use="generate-id(preceding-sibling::de[@name='16R'][. = 'FIN'][1])" />
    
      <xsl:output method="xml" indent="yes" />
    
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="catalog">
        <xsl:copy>
          <xsl:for-each select="de[@name='16R'][. = 'FIN']">
            <group>
              <xsl:apply-templates select="key('start', generate-id())[self::ds[@name='35B']]" mode="ds-35B" />
              <xsl:apply-templates select="key('start', generate-id())[self::ds[@name='93B'][de[@name='amount_type']='AGGR']][1]" mode="ds-93B" />
            </group>
          </xsl:for-each>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="ds" mode="ds-35B">
        <xsl:apply-templates select="de[@name='instrument_identification' or @name='instrument_type' or @name='instrument_code']" />
      </xsl:template>
    
      <xsl:template match="ds" mode="ds-93B">
        <xsl:apply-templates select="de[@name='amount']" />
      </xsl:template>
    
    </xsl:stylesheet>