0

My knowledge of XSLT is limited, so please forgive my ignorance. I am trying to create XML that has information about all failed steps across multiple execution servers. In the current setup,whenever a job is triggered, it can choose any of the available servers for execution. For each job failure that occurred during the day, an XML file is generated with details around the steps involved in execution. In the output summary XML, a step is considered failed based on the following rule:

<ERROR_CRITERIA>ALL</ERROR_CRITERIA> --- If the step fails across all the servers then it is considered failed.

<ERROR_CRITERIA>1</ERROR_CRITERIA> -- If it fails even on one server, it is considered failed. Here is my input XML

<ERROR>
    <SERVER>
        <SERVERID>1</SERVERID>
        <ERROR_SUBID>1234</ERROR_SUBID>
        <VALIDATION>
            <STEP>1</STEP>
            <PURPOSE>test</PURPOSE>
            <ERROR_CRITERIA>ALL</ERROR_CRITERIA>
            <STATUS>SUCCESS</STATUS>
            <MESSAGE>SUCCESSFULLY EXECUTED</MESSAGE>
        </VALIDATION>
        <VALIDATION>
            <STEP>2</STEP>
            <PURPOSE>test</PURPOSE>
            <ERROR_CRITERIA>1</ERROR_CRITERIA>
            <STATUS>FAILURE</STATUS>
            <MESSAGE>FAILED DUE TO NETWORK</MESSAGE>
        </VALIDATION>
    </SERVER>
    <SERVER>
        <SERVERID>2</SERVERID>
        <ERROR_SUBID>8765</ERROR_SUBID>
        <VALIDATION>
            <STEP>1</STEP>
            <PURPOSE>test1</PURPOSE>
            <ERROR_CRITERIA>ALL</ERROR_CRITERIA>
            <STATUS>FAILURE</STATUS>
            <MESSAGE>FAILED DUE TO ABC</MESSAGE>
        </VALIDATION>
        <VALIDATION>
            <STEP>2</STEP>
            <PURPOSE>test1</PURPOSE>
            <ERROR_CRITERIA>1</ERROR_CRITERIA>
            <STATUS>SUCCESS</STATUS>
            <MESSAGE>SUCCESSFULLY EXECUTED</MESSAGE>
        </VALIDATION>
    </SERVER>
    <SERVER>
        <SERVERID>3</SERVERID>
        <ERROR_SUBID>8065</ERROR_SUBID>
        <VALIDATION>
            <STEP>1</STEP>
            <PURPOSE>test2</PURPOSE>
            <ERROR_CRITERIA>ALL</ERROR_CRITERIA>
            <STATUS>FAILURE</STATUS>
            <MESSAGE>FAILED DUE TO 123</MESSAGE>
        </VALIDATION>
        <VALIDATION>
            <STEP>2</STEP>
            <PURPOSE>test2</PURPOSE>
            <ERROR_CRITERIA>1</ERROR_CRITERIA>
            <STATUS>SUCCESS</STATUS>
            <MESSAGE>SUCCESSFULLY EXECUTED</MESSAGE>
        </VALIDATION>
    </SERVER>
</ERROR>

I want to create XML with OUTPUT as:

<ERROR>
        <VALIDATION>
            <STEP>2</STEP>
            <ERROR_CRITERIA>1</ERROR_CRITERIA>
            <STATUS>FAILURE</STATUS>
            <MESSAGE>SERVERID_1:FAILED DUE TO NETWORK.SERVER_2:SUCCESSFULLY EXECUTED.SERVER_3:SUCCESSFULLY EXECUTED</MESSAGE>
        </VALIDATION>
</ERROR>

Since a job could have any number of steps, the solution needs to be dynamic to allow for any number of steps and servers.

Since I am not experienced with XSLT, I am not sure if custom business logic can be integrated. If not, I am most likely to use Python to accomplish it.

XSLT version 1.0

baati
  • 3
  • 2

1 Answers1

0

If I follow this correctly, you want do:

XSLT 1.0

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

<xsl:key name="val" match="VALIDATION" use="STEP" />

<xsl:template match="/ERROR">
    <xsl:copy>
        <!-- for each distinct step -->
        <xsl:for-each select="SERVER/VALIDATION[count(. | key('val', STEP)[1]) = 1]">
            <xsl:variable name="grp" select="key('val', STEP)" />
            <xsl:if test="ERROR_CRITERIA = '1' and $grp/STATUS = 'FAILURE' or ERROR_CRITERIA = 'ALL' and not($grp/STATUS = 'SUCCESS')">
                <xsl:copy>
                    <xsl:copy-of select="STEP | ERROR_CRITERIA"/>
                    <STATUS>FAILURE</STATUS>
                    <MESSAGE>
                        <xsl:for-each select="$grp">
                            <xsl:text>SERVERID_</xsl:text>
                            <xsl:value-of select="../SERVERID"/>
                            <xsl:text>:</xsl:text>
                            <xsl:value-of select="MESSAGE"/>
                            <xsl:if test="position() != last()">,</xsl:if>
                        </xsl:for-each>
                    </MESSAGE>
                </xsl:copy>
            </xsl:if>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

To understand how this works, you need to learn about Muenchian grouping.


If it can be assumed that each SERVER lists all the steps, then you can simplify this by changing:

    <xsl:for-each select="SERVER/VALIDATION[count(. | key('val', STEP)[1]) = 1]">

to:

    <xsl:for-each select="SERVER[1]/VALIDATION">
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51
  • I really appreciate your help! However, the message part of the output only shows the text from the first server. For example, if i set the step 2 status as "FAILURE" in SERVER =3 , the output xml reflect error message from server 1 only SERVERID_1:FAILED DUE TO NETWORK. – baati Nov 28 '22 at 21:15
  • That is not the result I get. – michael.hor257k Nov 28 '22 at 21:24
  • https://i.stack.imgur.com/lspRy.png --- I am using my intellij setup to test this solution – baati Nov 28 '22 at 22:05
  • There is something wrong with your testing environment. Or you are using a different code. Unfortunately, all the good online testers are currently down, but you can try https://xsltfiddle-beta.liberty-development.net/. – michael.hor257k Nov 28 '22 at 22:14
  • That's right, the issue was with the test environment. Thank you so much !! – baati Nov 28 '22 at 22:57