Mike Dole
Mike Dole

Reputation: 687

Delete parent xml element if in first step child elements are removed (issue with chaining)

I'm afraid I have to bother you again with a problem I can't solve myself :( I have an xml where I need an xsl for to do 2 things:

  1. Check if there are duplicate delivernr elements and remove them if there are more than 1
  2. Suppress TripOverView elements if there are no DropItem elements / if DropItems has no childeren

I hope you can help me with this?

Input xml

<?xml version="1.0" encoding="UTF-8"?>
<n0:MT_SmarTour_MultiTripOverview xmlns:n0="urn:deli.com:deli:erp:smartour_shipmentlist" xmlns:prx="urn:sap.com:proxy:SHQ:/1SAI/TASB581ED56DDF13679B0AC:754">
   <ShipmentDate>20231020</ShipmentDate>
   <ReportType>6</ReportType>
   <TripOverview>
      <HeaderDetails>
         <ShipmentNumber>0000319003</ShipmentNumber>
      </HeaderDetails>
   </TripOverview>
   <TripOverview>
      <HeaderDetails>
         <ShipmentNumber>0000319004</ShipmentNumber>
      </HeaderDetails>
   </TripOverview>
   <TripOverview>
      <HeaderDetails>
         <ShipmentNumber>0000400044</ShipmentNumber>
         <DropItems>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0082063404</DeliveryNr>
            </DropItem>
            <DropItem>
               <DropNr>02</DropNr>
               <DeliveryNr>0082063406</DeliveryNr>
            </DropItem>
            <DropItem>
               <DropNr>02</DropNr>
               <DeliveryNr>0082063405</DeliveryNr>
            </DropItem>
         </DropItems>
      </HeaderDetails>
   </TripOverview>
   <TripOverview>
      <HeaderDetails>
         <ShipmentNumber>0000400551</ShipmentNumber>
         <DropItems>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0084118934</DeliveryNr>
            </DropItem>
         </DropItems>
      </HeaderDetails>
   </TripOverview>
   <TripOverview>
      <HeaderDetails>
         <ShipmentNumber>0000400552</ShipmentNumber>
         <DropItems>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0082067282</DeliveryNr>
            </DropItem>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0082067283</DeliveryNr>
            </DropItem>
         </DropItems>
      </HeaderDetails>
   </TripOverview>
   <TripOverview>
      <HeaderDetails>
         <ShipmentNumber>0000400553</ShipmentNumber>
         <DropItems>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0082067285</DeliveryNr>
            </DropItem>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0082067284</DeliveryNr>
            </DropItem>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0082067286</DeliveryNr>
            </DropItem>
         </DropItems>
      </HeaderDetails>
   </TripOverview>
   <TripOverview>
      <HeaderDetails>
         <ShipmentNumber>0000400555</ShipmentNumber>
         <DropItems>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0082067285</DeliveryNr>
            </DropItem>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0082067284</DeliveryNr>
            </DropItem>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0082067286</DeliveryNr>
            </DropItem>
         </DropItems>
      </HeaderDetails>
   </TripOverview>
</n0:MT_SmarTour_MultiTripOverview>

Current xsl:

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

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

  <xsl:variable name="step1">
    <xsl:apply-templates mode="step1"/>
  </xsl:variable>

  <!-- Skip DropItems with duplicate deliveries (where the same deliverynr exist in multiple TripOverview -->
  <xsl:template mode="step1" match="DropItem[DeliveryNr = following::DeliveryNr]"/>

  <xsl:variable name="step2">
    <xsl:apply-templates select="$step1/node()" mode="step2"/>
  </xsl:variable>

  <!-- Skip TripOverview elements without DropItems/DropItem -->
  <xsl:template mode="step2" match="TripOverview[not(HeaderDetails/DropItems/DropItem)]"/>

  <xsl:variable name="step3">
    <xsl:apply-templates select="$step2/node()" mode="step3"/>
  </xsl:variable>

  <!-- Skip TripOverview elements without DropItems -->
  <xsl:template mode="step3" match="TripOverview[not(HeaderDetails/DropItems)]"/>
  
   <xsl:variable name="step4">
    <xsl:apply-templates select="$step3/node()" mode="step4"/>
  </xsl:variable>
  
  <!-- Remove whitespace-only text nodes -->
  <xsl:template mode="step4" match="text()[not(parent::*) and not(normalize-space())]"/>

</xsl:stylesheet>

I don't know if the chaining is required, I'm aware that after trying for quite some time I've made a mess of my efforts / xsl. The current output equals the input.

If I don't chain and my xsl looks like this:

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

  <!-- Copy all nodes as is except for TripOverview elements without DropItems -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  
  <!-- Skip DropItems with duplicate deliveries (where the same deliverynr exist in multiple TripOverview -->
  <xsl:template  match="DropItem[DeliveryNr = following::DeliveryNr]"/>

  <!-- Skip TripOverview elements without DropItems/DropItem -->
  <xsl:template  match="TripOverview[not(HeaderDetails/DropItems/DropItem)]"/>
  
  <!-- Skip TripOverview elements without DropItems -->
  <xsl:template match="TripOverview[not(HeaderDetails/DropItems)]"/>

</xsl:stylesheet>

The duplicate deliverynr elements are removed but I'm stuck with the (empty) TripOverview with no DropItems..

<?xml version="1.0" encoding="UTF-8"?>
<n0:MT_SmarTour_MultiTripOverview xmlns:n0="urn:deli.com:deli:erp:smartour_shipmentlist" xmlns:prx="urn:sap.com:proxy:SHQ:/1SAI/TASB581ED56DDF13679B0AC:754">
   <ShipmentDate>20231020</ShipmentDate>
   <ReportType>6</ReportType>
   <TripOverview>
      <HeaderDetails>
         <ShipmentNumber>0000400044</ShipmentNumber>
         <DropItems>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0082063404</DeliveryNr>
            </DropItem>
            <DropItem>
               <DropNr>02</DropNr>
               <DeliveryNr>0082063406</DeliveryNr>
            </DropItem>
            <DropItem>
               <DropNr>02</DropNr>
               <DeliveryNr>0082063405</DeliveryNr>
            </DropItem>
         </DropItems>
      </HeaderDetails>
   </TripOverview>
   <TripOverview>
      <HeaderDetails>
         <ShipmentNumber>0000400551</ShipmentNumber>
         <DropItems>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0084118934</DeliveryNr>
            </DropItem>
         </DropItems>
      </HeaderDetails>
   </TripOverview>
   <TripOverview>
      <HeaderDetails>
         <ShipmentNumber>0000400552</ShipmentNumber>
         <DropItems>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0082067282</DeliveryNr>
            </DropItem>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0082067283</DeliveryNr>
            </DropItem>
         </DropItems>
      </HeaderDetails>
   </TripOverview>
   <TripOverview>
      <HeaderDetails>
         <ShipmentNumber>0000400553</ShipmentNumber>
         <DropItems/>
      </HeaderDetails>
   </TripOverview>
   <TripOverview>
      <HeaderDetails>
         <ShipmentNumber>0000400555</ShipmentNumber>
         <DropItems>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0082067285</DeliveryNr>
            </DropItem>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0082067284</DeliveryNr>
            </DropItem>
            <DropItem>
               <DropNr>01</DropNr>
               <DeliveryNr>0082067286</DeliveryNr>
            </DropItem>
         </DropItems>
      </HeaderDetails>
   </TripOverview>
</n0:MT_SmarTour_MultiTripOverview>

My code / example xml might be more confusing than helping so I'll repeat my goal: From the input xml check for DeliveryNr elements which exist multiple times over X TripOverView elements and only keep the first. If the result has no DropItems or DropItems has no children delete the TripOverview elements.

Kind regards,

Mike

Upvotes: 0

Views: 40

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167641

Add

  <xsl:template match="/">
    <xsl:sequence select="$step4"/>
  </xsl:template>

and make sure you identity transformation template is "mode" safe:

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

Upvotes: 1

Related Questions