Jaisal
Jaisal

Reputation: 41

XSLT: Remove duplicate nodes based on name attribute

I have the below input XML which needs to be transformed with an xslt

Input Xml:

<result>
    <circuit>MX123456</circuit>
    <psaresult>
        <Live_Alarms>
            <diagnosis>
                <utr>xxx</utr>
                <dtr>xxx</dtr>
                <text />
                <site>xxx</site>
                <address />
                <tech_type />
                <end />
                <network_type>xxx</network_type>
            </diagnosis>
            <Alarms>
                <alarmId>463</alarmId>
                <cct>xxx</cct>
                <eventTime>12/05/11 09:21:21</eventTime>
                <clearTime />
                <problemCode>xxxx</problemCode>
                <problemText>xxxx</problemText>
                <equipmentName>xxx</equipmentName>
                <unit>xxx</unit>
                <rcKey>xxx</rcKey>
                <category>xxx</category>
                <rootCause>xxxx</rootCause>
            </Alarms>
            <Alarms>
                <alarmId>464</alarmId>
                <cct>xxx</cct>
                <eventTime>12/05/11 09:21:22</eventTime>
                <clearTime />
                <problemCode>yyyy</problemCode>
                <problemText>yyyy</problemText>
                <equipmentName>yyyy</equipmentName>
                <unit>yyyy</unit>
                <rcKey>yyyy</rcKey>
                <category>yyyy</category>
                <rootCause>yyyy</rootCause>
            </Alarms>
        </Live_Alarms>
    </psaresult>
</result>

Expected output:

<result>
    <circuit>MX123456</circuit>
    <psaresult>
        <Live_Alarms>
            <psadiagnosis>
                <utr>xxx</utr>
                <dtr>xxx</dtr>
                <text />
                <site>xxx</site>
                <address />
                <tech_type />
                <end />
                <network_type>xxx</network_type>
            </psadiagnosis>
            <Alarms>
                <alarmId>463</alarmId>
                <cct>xxx</cct>
                <eventTime>12/05/11 09:21:21</eventTime>
                <clearTime />
                <problemCode>xxxx</problemCode>
                <problemText>xxxx</problemText>
                <equipmentName>xxx</equipmentName>
                <unit>xxx</unit>
                <rcKey>xxx</rcKey>
                <category>xxx</category>
                <rootCause>xxxx</rootCause>
            </Alarms>
        </Live_Alarms>
    </psaresult>
</result>

Note: Ony the first Alarms node is needed like what SelectSinglenode does and all others needed to be truncated from the output. Can you please advise how this can be achieved from an xslt?

Upvotes: 4

Views: 1055

Answers (2)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243599

Here is the canonical identity rule - based solution:

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

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

 <xsl:template match="Alarms[position() >1]"/>
</xsl:stylesheet>

When applied on the provided XML document:

<result>
    <circuit>MX123456</circuit>
    <psaresult>
        <Live_Alarms>
            <diagnosis>
                <utr>xxx</utr>
                <dtr>xxx</dtr>
                <text />
                <site>xxx</site>
                <address />
                <tech_type />
                <end />
                <network_type>xxx</network_type>
            </diagnosis>
            <Alarms>
                <alarmId>463</alarmId>
                <cct>xxx</cct>
                <eventTime>12/05/11 09:21:21</eventTime>
                <clearTime />
                <problemCode>xxxx</problemCode>
                <problemText>xxxx</problemText>
                <equipmentName>xxx</equipmentName>
                <unit>xxx</unit>
                <rcKey>xxx</rcKey>
                <category>xxx</category>
                <rootCause>xxxx</rootCause>
            </Alarms>
            <Alarms>
                <alarmId>464</alarmId>
                <cct>xxx</cct>
                <eventTime>12/05/11 09:21:22</eventTime>
                <clearTime />
                <problemCode>yyyy</problemCode>
                <problemText>yyyy</problemText>
                <equipmentName>yyyy</equipmentName>
                <unit>yyyy</unit>
                <rcKey>yyyy</rcKey>
                <category>yyyy</category>
                <rootCause>yyyy</rootCause>
            </Alarms>
        </Live_Alarms>
    </psaresult>
</result>

exactly the wanted, correct result is produced:

<result>
   <circuit>MX123456</circuit>
   <psaresult>
      <Live_Alarms>
         <diagnosis>
            <utr>xxx</utr>
            <dtr>xxx</dtr>
            <text/>
            <site>xxx</site>
            <address/>
            <tech_type/>
            <end/>
            <network_type>xxx</network_type>
         </diagnosis>
         <Alarms>
            <alarmId>463</alarmId>
            <cct>xxx</cct>
            <eventTime>12/05/11 09:21:21</eventTime>
            <clearTime/>
            <problemCode>xxxx</problemCode>
            <problemText>xxxx</problemText>
            <equipmentName>xxx</equipmentName>
            <unit>xxx</unit>
            <rcKey>xxx</rcKey>
            <category>xxx</category>
            <rootCause>xxxx</rootCause>
         </Alarms>
      </Live_Alarms>
   </psaresult>
</result>

Explanation:

  1. The identity rule (template) copies every node "as-is".

  2. There is a single template overriding the identity rule. It matches any Alarms element that isn't the first Alarms child of its parent. This template has no body -- effectively discarding any such matched element from being copied into the output.

Upvotes: 2

Kirill Polishchuk
Kirill Polishchuk

Reputation: 56222

Use this:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()[not(self::Alarms)] | Alarms[1]"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Output XML:

<?xml version="1.0" encoding="utf-8"?>
<result>
    <circuit>MX123456</circuit>
    <psaresult>
        <Live_Alarms>
            <diagnosis>
                <utr>xxx</utr>
                <dtr>xxx</dtr>
                <text />
                <site>xxx</site>
                <address />
                <tech_type />
                <end />
                <network_type>xxx</network_type>
            </diagnosis>
            <Alarms>
                <alarmId>463</alarmId>
                <cct>xxx</cct>
                <eventTime>12/05/11 09:21:21</eventTime>
                <clearTime />
                <problemCode>xxxx</problemCode>
                <problemText>xxxx</problemText>
                <equipmentName>xxx</equipmentName>
                <unit>xxx</unit>
                <rcKey>xxx</rcKey>
                <category>xxx</category>
                <rootCause>xxxx</rootCause>
            </Alarms>


        </Live_Alarms>
    </psaresult>

</result>

Upvotes: 0

Related Questions