Search code examples
xmlxslttibco

get a tag value based on another tag value from each record using xslt


I need to get an element value based on another element value from each record. I have to have them as two groups based on the second element value.

The criteria:

  • if RECORD_TYPE='WARNING' then I have to print all the ERROR_DESC values for all records under WARNINGS:.

  • if RECORD_TYPE='ERROR' then I have to print all the ERROR_DESC values for all records under ERRORS:

  • Each error description should be printed in a new line.

Example input:

<root>
<SellOutErrorRecord>
    <RECORD_TYPE>WARNING</RECORD_TYPE>
    <ERROR_DESC>record 1:location id is invalid</ERROR_DESC>
    <RECORD_NO>1</RECORD_NO>
    <LOCATION_NAME>XYZ el</LOCATION_NAME>
    <PRODUCT_NUMBER>336549R-001</PRODUCT_NUMBER>
    <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
    <PRODUCT_LINE>LA</PRODUCT_LINE>
</SellOutErrorRecord>
<SalesInErrorRecord>
    <RECORD_TYPE>ERROR</RECORD_TYPE>
    <ERROR_DESC>record 1:location id is invalid</ERROR_DESC>
    <RECORD_NO>1</RECORD_NO>
    <LOCATION_NAME>XYZ el</LOCATION_NAME>
    <PRODUCT_NUMBER>336549R-001</PRODUCT_NUMBER>
    <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
    <PRODUCT_LINE>LA</PRODUCT_LINE>
    <PRODUCT_LINE_TYPE>C</PRODUCT_LINE_TYPE>
</SalesInErrorRecord>
<SellOutErrorRecord>
    <RECORD_TYPE>ERROR</RECORD_TYPE>
    <ERROR_DESC>record 2:SO:invoiced net amount is invalid</ERROR_DESC>
    <RECORD_NO>2</RECORD_NO>
    <LOCATION_NAME>XYZ el</LOCATION_NAME>
    <PRODUCT_NUMBER>3X-KN73C-DB</PRODUCT_NUMBER>
    <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
    <PRODUCT_LINE>HA</PRODUCT_LINE>
    <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
</SellOutErrorRecord>
<SellOutErrorRecord>
    <RECORD_TYPE>ERROR</RECORD_TYPE>
    <ERROR_DESC>record 3:SO:transaction currency is invalid</ERROR_DESC>
    <RECORD_NO>3</RECORD_NO>
    <LOCATION_NAME>XYZ el</LOCATION_NAME>
    <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
    <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
    <PRODUCT_LINE>J3</PRODUCT_LINE>
    <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
</SellOutErrorRecord>
<SalesInErrorRecord>
    <RECORD_TYPE>WARNING</RECORD_TYPE>
    <ERROR_DESC>record 3:SI:buy quantity is zero</ERROR_DESC>
    <RECORD_NO>3</RECORD_NO>
    <LOCATION_NAME>XYZ el</LOCATION_NAME>
    <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
    <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
    <PRODUCT_LINE>J3</PRODUCT_LINE>
    <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
</SalesInErrorRecord>
<SalesInErrorRecord>
    <RECORD_TYPE>ERROR</RECORD_TYPE>
    <ERROR_DESC>record 3:SI:transaction document id is invalid</ERROR_DESC>
    <RECORD_NO>3</RECORD_NO>
    <LOCATION_NAME>XYZ el</LOCATION_NAME>
    <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
    <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
    <PRODUCT_LINE>J3</PRODUCT_LINE>
    <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
</SalesInErrorRecord>
<SellOutErrorRecord>
    <RECORD_TYPE>WARNING</RECORD_TYPE>
    <ERROR_DESC>record 4:SO:invoiced net amount is invalid</ERROR_DESC>
    <RECORD_NO>4</RECORD_NO>
    <LOCATION_NAME>XYZ el</LOCATION_NAME>
    <PRODUCT_NUMBER>445860-B21</PRODUCT_NUMBER>
    <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
    <PRODUCT_LINE>MV</PRODUCT_LINE>
    <PRODUCT_LINE_TYPE>C</PRODUCT_LINE_TYPE>
</SellOutErrorRecord>
<SalesInErrorRecord>
    <RECORD_TYPE>ERROR</RECORD_TYPE>
    <ERROR_DESC>record 5:SI:transaction currency is null or invalid</ERROR_DESC>
    <RECORD_NO>5</RECORD_NO>
    <LOCATION_NAME>XYZ el</LOCATION_NAME>
    <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
    <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
    <PRODUCT_LINE>J3</PRODUCT_LINE>
    <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
</SalesInErrorRecord>
<InventoryErrorRecord>
    <RECORD_TYPE>ERROR</RECORD_TYPE>
    <ERROR_DESC>record 6:product id is invalid</ERROR_DESC>
    <RECORD_NO>6</RECORD_NO>
    <LOCATION_NAME>XYZ XYZ</LOCATION_NAME>
    <PRODUCT_NUMBER>331184-B21</PRODUCT_NUMBER>
    <PRODUCT_OPTION>0S1</PRODUCT_OPTION>
    <PRODUCT_LINE>R8</PRODUCT_LINE>
    <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
</InventoryErrorRecord>
<SellOutErrorRecord>
    <RECORD_TYPE>ERROR</RECORD_TYPE>
    <ERROR_DESC>record 6:SO:invoiced net amount is invalid</ERROR_DESC>
    <RECORD_NO>6</RECORD_NO>
    <LOCATION_NAME>XYZ el</LOCATION_NAME>
    <PRODUCT_NUMBER>339112-B25</PRODUCT_NUMBER>
    <PRODUCT_OPTION>0D1</PRODUCT_OPTION>
    <PRODUCT_LINE>J3</PRODUCT_LINE>
    <PRODUCT_LINE_TYPE>E</PRODUCT_LINE_TYPE>
</SellOutErrorRecord>
</root>

The expected output:

ERRORS:
record 1:location id is invalid
record 2:SO:invoiced net amount is invalid
record 3:SO:transaction currency is invalid

WARNINGS:
record 1:location id is invalid
record 3:SI:buy quantity is zero
record 4:SO:invoiced net amount is invalid

Solution

  • The following stylesheet uses xsl:key in order to group the elements by their RECORD_TYPE value and generate the grouped text output.

    <xsl:stylesheet version="1.0"      
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  
        <xsl:output method="text"/>
    
        <!--Create a key matching on each of the elements that contain RECORD_TYPE, and use it's value as the lookup key -->
        <xsl:key name="record-type" match="*[RECORD_TYPE]" use="RECORD_TYPE" />
    
        <xsl:template match="/">
            <!--generate output for all ERRORS -->
            <xsl:apply-templates select="key('record-type','ERROR')" />
            <!--generate a line-feed to separate the record types -->
            <xsl:text>&#xA;</xsl:text>
            <!--generate output for all WARNINGS -->
            <xsl:apply-templates select="key('record-type','WARNING')" />
        </xsl:template>
    
       <!--For the first of each type of record, generate a header row -->
       <xsl:template match="/*/*[generate-id()=generate-id(key('record-type',RECORD_TYPE)[1])]">
           <xsl:value-of select="RECORD_TYPE"/>
            <xsl:text>S:&#xA;</xsl:text>           
            <xsl:apply-templates select="ERROR_DESC" />
       </xsl:template>
    
        <!--Default processing for elements is to apply-templates to child elements-->
        <xsl:template match="*">
            <xsl:apply-templates select="*"/>
        </xsl:template>
    
        <!--For ERROR_DESC, output it's text value and a line-feed -->
        <xsl:template match="ERROR_DESC">
            <xsl:value-of select="."/>
            <xsl:text>&#xA;</xsl:text>
        </xsl:template>
    
    </xsl:stylesheet>
    

    When applied to the XML provided, it produces the following output:

    ERRORS:
    record 1:location id is invalid
    record 2:SO:invoiced net amount is invalid
    record 3:SO:transaction currency is invalid
    record 3:SI:transaction document id is invalid
    record 5:SI:transaction currency is null or invalid
    record 6:product id is invalid
    record 6:SO:invoiced net amount is invalid
    
    WARNINGS:
    record 1:location id is invalid
    record 3:SI:buy quantity is zero
    record 4:SO:invoiced net amount is invalid