function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Tony Williams 9Tony Williams 9 

Traversing XML Trees using Apex

HI I'm trying top traverse an XML tree to get the Items Tag list. I was using iterative but the problem is that it seems that I can only get the lst item but I don;t get them all. Can someone p0leaswe help me?  Thanks Here's the tree:
 
<Shipment id="103052074"> 
    <ClientName>Awana</ClientName> 
    <OrderID>01061767</OrderID> 
    <PurchaseOrder /> 
    <Name>SILVIA GIBSON</Name> 
    <FirstName>SILVIA</FirstName> 
    <LastName>GIBSON</LastName> 
    <Company /> 
    <Address1>11900 TRADITION LN NE </Address1> 
    <Address2 /> 
    <City>ALBUQUERQUE</City> 
    <State>NM</State> 
    <PostalCode>87111-8287</PostalCode> 
    <Country>UNITED STATES</Country> 
    <Email>silviagibson@mailinator.com</Email> 
    <Phone /> 
    <OrderTimestamp>2019-01-18T00:00:00</OrderTimestamp> 
    <ReceivedTimestamp>2019-01-18T13:59:26.007</ReceivedTimestamp> 
    <ShipmentStatus>SHIPPED</ShipmentStatus> 
    <OrderType>Consumer</OrderType> 
    <ShippedDate>2019-01-18T14:16:37.550</ShippedDate> 
    <ExpectedDeliveryDate>2019-01-18T00:00:00</ExpectedDeliveryDate> <DeliveredTimestamp /> <DeliveryException />             
    <Warehouse id="160"> 
       <Name>Greenwood, IN</Name> 
       <Address>1415 Collins Rd.</Address> 
       <City>Greenwood</City> 
       <State>IN</State> 
       <PostalCode>46143</PostalCode> 
       <Country>US</Country> 
    </Warehouse> 
    <ShipMethod>Newgistics Parcel Select</ShipMethod> 
    <ShipMethodCode>NGSPS</ShipMethodCode> 
    <Tracking>9200000000000629213249</Tracking>                  <TrackingUrl>http://shipment.co/tracking/2817/9200000000000629213249</TrackingUrl> 
     <Weight>4.000000</Weight> 
     <Postage /> 
     <GiftWrap>false</GiftWrap> 
     <CustomFields> 
         <BillingAddress1>1620 N Penny Ln</BillingAddress1> 
         <BillingCity>Schaumburg</BillingCity> 
         <BillingCompany>Cherry Hills Community Church</BillingCompany> 
         <BillingCountry>United States</BillingCountry> 
         <BillingEmail>silviagibson@mailinator.com</BillingEmail> 
         <BillingFirstName>Heather</BillingFirstName> 
         <BillingLastName>Oliver</BillingLastName> 
         <BillingPhone>(866) 292-6227</BillingPhone> 
         <BillingState>IL</BillingState> 
          <BillingZip>60173</BillingZip> 
           <Shipping>17.87</Shipping> 
           <Total>190.52</Total> 
      </CustomFields> 
      <BackorderedItems /> 
      <Items> 
         <Item id="1807577"> 
               <SKU>94900</SKU> 
                <UPC /> 
                 <Description>Cubbies AppleSeed Handbook Music CD NIV</Description> 
                <Lot /> 
                <Qty>2</Qty> 
               <CustomFields /> 
               <AssemblyItems /> 
       </Item> 
      <Item id="1807606"> 
             <SKU>96543</SKU> 
             <UPC /> 
             <Description>Cubbies HoneyComb Teaching Plans NKJV</Description> 
             <Lot /> 
             <Qty>1</Qty> 
             <CustomFields />  
             <AssemblyItems /> 
      </Item> 
      <Item id="1807670"> 
           <SKU>96918</SKU> 
           <UPC /> 
           <Description>Game Pin (4)</Description> 
           <Lot /> 
           <Qty>4</Qty> 
           <CustomFields /> 
           <AssemblyItems /> 
     </Item> 
        <Item id="1807691"> 
          <SKU>46421</SKU> 
          <UPC /> 
          <Description>Gray Blouse, Leader Size 4X</Description> <Lot /> 
         <Qty>3</Qty> <CustomFields /> 
          <AssemblyItems /> 
     </Item> 
  </Items> 
 <Packages> 
   <Package id="86892375"> 
      <TrackingNumber>9200000000000629213249</TrackingNumber>
      <Weight>4.30507</Weight> 
      <BillableWeight>4.00000</BillableWeight> 
      <Height>7.00000</Height> 
      <Width>4.00000</Width>  
      <Depth>6.00000</Depth> 
</Package>
</Shipment> 

 
Best Answer chosen by Tony Williams 9
Alain CabonAlain Cabon
Hi,

You just want the <items> <Item id="1807577"> ... </item> </items>

There is a mistake in your xml source   <Packages>

If you just install this class you can use a subset of XPathhttps://github.com/JenniferSimonds/apex-xpath/blob/1.0.1/XPath.cls
https://github.com/JenniferSimonds/apex-xpath

Dom.XmlNode[] items = xp.find('/Shipment/Items/Item');

You just need this XPath expression : /Shipment/Items/Item   (  shortest way to get all the items )
 
String xml = '<Shipment id="103052074"> \n' +
'    <ClientName>Awana</ClientName> \n' +
'    <OrderID>01061767</OrderID> \n' +
'    <PurchaseOrder /> \n' +
'    <Name>SILVIA GIBSON</Name> \n' +
'    <FirstName>SILVIA</FirstName> \n' +
'    <LastName>GIBSON</LastName> \n' +
'    <Company /> \n' +
'    <Address1>11900 TRADITION LN NE </Address1> \n' +
'    <Address2 /> \n' +
'    <City>ALBUQUERQUE</City> \n' +
'    <State>NM</State> \n' +
'    <PostalCode>87111-8287</PostalCode> \n' +
'    <Country>UNITED STATES</Country> \n' +
'    <Email>silviagibson@mailinator.com</Email> \n' +
'    <Phone /> \n' +
'    <OrderTimestamp>2019-01-18T00:00:00</OrderTimestamp> \n' +
'    <ReceivedTimestamp>2019-01-18T13:59:26.007</ReceivedTimestamp> \n' +
'    <ShipmentStatus>SHIPPED</ShipmentStatus> \n' +
'    <OrderType>Consumer</OrderType> \n' +
'    <ShippedDate>2019-01-18T14:16:37.550</ShippedDate> \n' +
'    <ExpectedDeliveryDate>2019-01-18T00:00:00</ExpectedDeliveryDate> <DeliveredTimestamp /> <DeliveryException />             \n' +
'    <Warehouse id="160"> \n' +
'       <Name>Greenwood, IN</Name> \n' +
'       <Address>1415 Collins Rd.</Address> \n' +
'       <City>Greenwood</City> \n' +
'       <State>IN</State> \n' +
'       <PostalCode>46143</PostalCode> \n' +
'       <Country>US</Country> \n' +
'    </Warehouse> \n' +
'    <ShipMethod>Newgistics Parcel Select</ShipMethod> \n' +
'    <ShipMethodCode>NGSPS</ShipMethodCode> \n' +
'    <Tracking>9200000000000629213249</Tracking>                  <TrackingUrl>http://shipment.co/tracking/2817/9200000000000629213249</TrackingUrl> \n' +
'     <Weight>4.000000</Weight> \n' +
'     <Postage /> \n' +
'     <GiftWrap>false</GiftWrap> \n' +
'     <CustomFields> \n' +
'         <BillingAddress1>1620 N Penny Ln</BillingAddress1> \n' +
'         <BillingCity>Schaumburg</BillingCity> \n' +
'         <BillingCompany>Cherry Hills Community Church</BillingCompany> \n' +
'         <BillingCountry>United States</BillingCountry> \n' +
'         <BillingEmail>silviagibson@mailinator.com</BillingEmail> \n' +
'         <BillingFirstName>Heather</BillingFirstName> \n' +
'         <BillingLastName>Oliver</BillingLastName> \n' +
'         <BillingPhone>(866) 292-6227</BillingPhone> \n' +
'         <BillingState>IL</BillingState> \n' +
'          <BillingZip>60173</BillingZip> \n' +
'           <Shipping>17.87</Shipping> \n' +
'           <Total>190.52</Total> \n' +
'      </CustomFields> \n' +
'      <BackorderedItems /> \n' +
'      <Items> \n' +
'         <Item id="1807577"> \n' +
'               <SKU>94900</SKU> \n' +
'                <UPC /> \n' +
'                 <Description>Cubbies AppleSeed Handbook Music CD NIV</Description> \n' +
'                <Lot /> \n' +
'                <Qty>2</Qty> \n' +
'               <CustomFields /> \n' +
'               <AssemblyItems /> \n' +
'       </Item> \n' +
'      <Item id="1807606"> \n' +
'             <SKU>96543</SKU> \n' +
'             <UPC /> \n' +
'             <Description>Cubbies HoneyComb Teaching Plans NKJV</Description> \n' +
'             <Lot /> \n' +
'             <Qty>1</Qty> \n' +
'             <CustomFields />  \n' +
'             <AssemblyItems /> \n' +
'      </Item> \n' +
'      <Item id="1807670"> \n' +
'           <SKU>96918</SKU> \n' +
'           <UPC /> \n' +
'           <Description>Game Pin (4)</Description> \n' +
'           <Lot /> \n' +
'           <Qty>4</Qty> \n' +
'           <CustomFields /> \n' +
'           <AssemblyItems /> \n' +
'     </Item> \n' +
'        <Item id="1807691"> \n' +
'          <SKU>46421</SKU> \n' +
'          <UPC /> \n' +
'          <Description>Gray Blouse, Leader Size 4X</Description> <Lot /> \n' +
'         <Qty>3</Qty> <CustomFields /> \n' +
'          <AssemblyItems /> \n' +
'     </Item> \n' +
'  </Items> \n' +
'   <Package id="86892375"> \n' +
'      <TrackingNumber>9200000000000629213249</TrackingNumber>\n' +
'      <Weight>4.30507</Weight> \n' +
'      <BillableWeight>4.00000</BillableWeight> \n' +
'      <Height>7.00000</Height> \n' +
'      <Width>4.00000</Width>  \n' +
'      <Depth>6.00000</Depth> \n' +
'</Package>\n' +
'</Shipment> \n';
  
XPath xp = new XPath(xml);
Dom.XmlNode[] items = xp.find('/Shipment/Items/Item');

for (Dom.XmlNode item : items) {
    String item_id = item.getAttribute('id',null);   
    String item_weight = xp.getText(item, '', './SKU');
    String item_description = xp.getText(item, '', './Description');  
    system.debug('item:' + item_id + ' = ' + item_weight + ' = ' + item_description);
}

 

All Answers

Alain CabonAlain Cabon
Hi,

You just want the <items> <Item id="1807577"> ... </item> </items>

There is a mistake in your xml source   <Packages>

If you just install this class you can use a subset of XPathhttps://github.com/JenniferSimonds/apex-xpath/blob/1.0.1/XPath.cls
https://github.com/JenniferSimonds/apex-xpath

Dom.XmlNode[] items = xp.find('/Shipment/Items/Item');

You just need this XPath expression : /Shipment/Items/Item   (  shortest way to get all the items )
 
String xml = '<Shipment id="103052074"> \n' +
'    <ClientName>Awana</ClientName> \n' +
'    <OrderID>01061767</OrderID> \n' +
'    <PurchaseOrder /> \n' +
'    <Name>SILVIA GIBSON</Name> \n' +
'    <FirstName>SILVIA</FirstName> \n' +
'    <LastName>GIBSON</LastName> \n' +
'    <Company /> \n' +
'    <Address1>11900 TRADITION LN NE </Address1> \n' +
'    <Address2 /> \n' +
'    <City>ALBUQUERQUE</City> \n' +
'    <State>NM</State> \n' +
'    <PostalCode>87111-8287</PostalCode> \n' +
'    <Country>UNITED STATES</Country> \n' +
'    <Email>silviagibson@mailinator.com</Email> \n' +
'    <Phone /> \n' +
'    <OrderTimestamp>2019-01-18T00:00:00</OrderTimestamp> \n' +
'    <ReceivedTimestamp>2019-01-18T13:59:26.007</ReceivedTimestamp> \n' +
'    <ShipmentStatus>SHIPPED</ShipmentStatus> \n' +
'    <OrderType>Consumer</OrderType> \n' +
'    <ShippedDate>2019-01-18T14:16:37.550</ShippedDate> \n' +
'    <ExpectedDeliveryDate>2019-01-18T00:00:00</ExpectedDeliveryDate> <DeliveredTimestamp /> <DeliveryException />             \n' +
'    <Warehouse id="160"> \n' +
'       <Name>Greenwood, IN</Name> \n' +
'       <Address>1415 Collins Rd.</Address> \n' +
'       <City>Greenwood</City> \n' +
'       <State>IN</State> \n' +
'       <PostalCode>46143</PostalCode> \n' +
'       <Country>US</Country> \n' +
'    </Warehouse> \n' +
'    <ShipMethod>Newgistics Parcel Select</ShipMethod> \n' +
'    <ShipMethodCode>NGSPS</ShipMethodCode> \n' +
'    <Tracking>9200000000000629213249</Tracking>                  <TrackingUrl>http://shipment.co/tracking/2817/9200000000000629213249</TrackingUrl> \n' +
'     <Weight>4.000000</Weight> \n' +
'     <Postage /> \n' +
'     <GiftWrap>false</GiftWrap> \n' +
'     <CustomFields> \n' +
'         <BillingAddress1>1620 N Penny Ln</BillingAddress1> \n' +
'         <BillingCity>Schaumburg</BillingCity> \n' +
'         <BillingCompany>Cherry Hills Community Church</BillingCompany> \n' +
'         <BillingCountry>United States</BillingCountry> \n' +
'         <BillingEmail>silviagibson@mailinator.com</BillingEmail> \n' +
'         <BillingFirstName>Heather</BillingFirstName> \n' +
'         <BillingLastName>Oliver</BillingLastName> \n' +
'         <BillingPhone>(866) 292-6227</BillingPhone> \n' +
'         <BillingState>IL</BillingState> \n' +
'          <BillingZip>60173</BillingZip> \n' +
'           <Shipping>17.87</Shipping> \n' +
'           <Total>190.52</Total> \n' +
'      </CustomFields> \n' +
'      <BackorderedItems /> \n' +
'      <Items> \n' +
'         <Item id="1807577"> \n' +
'               <SKU>94900</SKU> \n' +
'                <UPC /> \n' +
'                 <Description>Cubbies AppleSeed Handbook Music CD NIV</Description> \n' +
'                <Lot /> \n' +
'                <Qty>2</Qty> \n' +
'               <CustomFields /> \n' +
'               <AssemblyItems /> \n' +
'       </Item> \n' +
'      <Item id="1807606"> \n' +
'             <SKU>96543</SKU> \n' +
'             <UPC /> \n' +
'             <Description>Cubbies HoneyComb Teaching Plans NKJV</Description> \n' +
'             <Lot /> \n' +
'             <Qty>1</Qty> \n' +
'             <CustomFields />  \n' +
'             <AssemblyItems /> \n' +
'      </Item> \n' +
'      <Item id="1807670"> \n' +
'           <SKU>96918</SKU> \n' +
'           <UPC /> \n' +
'           <Description>Game Pin (4)</Description> \n' +
'           <Lot /> \n' +
'           <Qty>4</Qty> \n' +
'           <CustomFields /> \n' +
'           <AssemblyItems /> \n' +
'     </Item> \n' +
'        <Item id="1807691"> \n' +
'          <SKU>46421</SKU> \n' +
'          <UPC /> \n' +
'          <Description>Gray Blouse, Leader Size 4X</Description> <Lot /> \n' +
'         <Qty>3</Qty> <CustomFields /> \n' +
'          <AssemblyItems /> \n' +
'     </Item> \n' +
'  </Items> \n' +
'   <Package id="86892375"> \n' +
'      <TrackingNumber>9200000000000629213249</TrackingNumber>\n' +
'      <Weight>4.30507</Weight> \n' +
'      <BillableWeight>4.00000</BillableWeight> \n' +
'      <Height>7.00000</Height> \n' +
'      <Width>4.00000</Width>  \n' +
'      <Depth>6.00000</Depth> \n' +
'</Package>\n' +
'</Shipment> \n';
  
XPath xp = new XPath(xml);
Dom.XmlNode[] items = xp.find('/Shipment/Items/Item');

for (Dom.XmlNode item : items) {
    String item_id = item.getAttribute('id',null);   
    String item_weight = xp.getText(item, '', './SKU');
    String item_description = xp.getText(item, '', './Description');  
    system.debug('item:' + item_id + ' = ' + item_weight + ' = ' + item_description);
}

 
This was selected as the best answer
Tony Williams 9Tony Williams 9
Thanks Alain, my code was doing it this way using Dom.Document and picking off the child nodes recursively.
public class SearchShipmentRequest {
  //  @future (callout=true) // future method needed to run callouts from Triggers
   public List<NGUtilityClasses.Shipment> ShipmentResponses = new List<NGUtilityClasses.Shipment>();    // pro
    NGUtilityClasses.Shipment   ShipmentResponse = new NGUtilityClasses.Shipment(); 
   // NGUtilityClasses.Fee ngFees;
    //NGUtilityClasses.BackorderedItem boInfo;
    NGUtilityClasses.Item itemInfo;
   // NGUtilityClasses.NGPackage pkgInfo;
    NGUtilityClasses.Warehouse warehouse;
    NGUtilityClasses.DeliveryExcept deliveryException;
    NGUtilityClasses.Item somePkgItem; 
    
    //String XMLString;
    
    public SearchShipmentRequest(String xml){
         // Send the Search Shipment Request
           try
             {
           		// Read through the XML
                DOM.Document doc = new DOM.Document();
                 if(xml != '' && xml != null){
                	//system.debug('<< RESPONSE XML FROM NG >> '+xml);
                	doc.load(xml);
                	DOM.XmlNode rootNode = doc.getRootElement();   
          	  		parseXML(rootNode);
                   
                	ShipmentResponses.add(ShipmentResponse); 
                     system.debug('<< SHipment Responses >> '+ShipmentResponses);
                 }else{
                     system.debug('<< No Data Was Read from NG Server>>');
                 }
             }catch(Exception ex)
             {
                 system.debug('There was an exception that occurred while processing the Shipment Repsonse '+ex.getMessage());
                 system.debug('<< Stack Trace >> '+ex.getStackTraceString()+' << Line Number >> '+ex.getLineNumber());
             }
       }//Method 
// Add Pareser method here

   /*******************************************************************************
      parseXML:
    1.Parses the Post Shipment Response message for Shipment ID
    2.Parses the Post Shipment Response message for Order ID.
   *******************************************************************************/    
   // private static List<String> traverseXMLRecurse(DOM.XMLNode node,NGUtilityClasses.Shipment ShipmentResponse) {
   private void parseXML(DOM.XMLNode node) {
  		if (node.getNodeType() == DOM.XMLNodeType.ELEMENT) {
           // system.debug(node.getName()+'<< TEXT >> '+node.getText().trim());
            if(node.getName() == 'Shipment'){
               	ShipmentResponse = new NGUtilityClasses.Shipment();
                if (node.getAttributeCount() > 0){
                	ShipmentResponse.shipmentID = node.getAttributeValue(node.getAttributeKeyAt(0), node.getAttributeKeyNsAt(0));
                }
                if(ShipmentResponse !=null ){
               		ShipmentResponses.add(ShipmentResponse);
                }
            } 
            if(node.getName() == 'ClientName'){if(node.getText().trim() !=null){ShipmentResponse.clientName = node.getText().trim();}}
            if(node.getName() == 'OrderID'){if(node.getText().trim() !=null){ShipmentResponse.orderID = node.getText().trim();}}
            if(node.getName() =='PurchaseOrder'){if(node.getText().trim() !=null){ShipmentResponse.purchaseOrder = node.getText().trim();}}
            if(node.getName() =='NAME'){if(node.getText().trim() !=null){ShipmentResponse.name = node.getText().trim();}}
            if(node.getName() =='FirstName'){if(node.getText().trim() !=null){ShipmentResponse.firstname= node.getText().trim();}}
            if(node.getName() =='LastName'){if(node.getText().trim() !=null){ShipmentResponse.lastname = node.getText().trim();}}
            if(node.getName() =='Company'){if(node.getText().trim() !=null){ShipmentResponse.company = node.getText().trim();}}
            if(node.getName() =='Address1'){if(node.getText().trim() !=null){ShipmentResponse.address1 = node.getText().trim();}}
            if(node.getName() =='Address2'){if(node.getText().trim() !=null){ShipmentResponse.address2 = node.getText().trim();}}
            if(node.getName() =='City'){if(node.getText().trim() !=null){ShipmentResponse.city = node.getText().trim();}}
            if(node.getName() =='State'){if(node.getText().trim() !=null){ShipmentResponse.state = node.getText().trim();}}
            if(node.getName() =='PostalCode'){if(node.getText().trim() !=null){ShipmentResponse.postalCode = node.getText().trim();}}
            if(node.getName() =='Country'){if(node.getText().trim() !=null){ShipmentResponse.country = node.getText().trim();}}
            if(node.getName() =='Email'){if(node.getText().trim() !=null){ShipmentResponse.email = node.getText().trim();}}
            if(node.getName() =='Phone'){if(node.getText().trim() !=null){ShipmentResponse.phone = node.getText().trim();}}
            if(node.getName() =='OrderTimestamp'){if(node.getText().trim() !=null){ShipmentResponse.orderTimeStamp = node.getText().trim();}}
            if(node.getName() =='ReceivedTimestamp'){if(node.getText().trim() !=null){ShipmentResponse.receivedTimestamp = node.getText().trim();}}
            if(node.getName() =='ShipmentStatus'){if(node.getText().trim() !=null){ShipmentResponse.shipmentStatus = node.getText().trim();}}
            if(node.getName() =='OrderType'){if(node.getText().trim() !=null){ShipmentResponse.orderType = node.getText().trim();}}
            if(node.getName() =='ShippedDate'){if(node.getText().trim() !=null){ShipmentResponse.ShippedDate = node.getText().trim();}}
            if(node.getName() =='ExpectedDeliveryDate'){if(node.getText().trim() !=null){ShipmentResponse.ExpectedDeliveryDate = node.getText().trim();}}
            if(node.getName() =='DeliveredTimestamp'){if(node.getText().trim() !=null){ShipmentResponse.DeliveredTimestamp = node.getText().trim();}}
            if(node.getName() =='ShipMethod'){if(node.getText().trim() !=null){ShipmentResponse.shipMethod = node.getText().trim(); }}
            if(node.getName() =='ShipMethodCode'){if(node.getText().trim() !=null){ShipmentResponse.shipMethodCode = node.getText().trim();}}
            if(node.getName() =='Tracking'){if(node.getText().trim() !=null){ShipmentResponse.tracking = node.getText().trim();}}
            if(node.getName() =='TrackingUrl'){if(node.getText().trim() !=null){ShipmentResponse.trackingUrl = node.getText().trim();}}
            if(node.getName() =='Weight'){if(node.getText().trim() !=null){ShipmentResponse.weight = node.getText().trim();}}
            if(node.getName() =='Postage'){if(node.getText().trim() !=null){ShipmentResponse.postage = node.getText().trim();}} 
            if(node.getName() == 'DeliveryException'){
                deliveryException = new  NGUtilityClasses.DeliveryExcept();
             	ShipmentResponse.aDeliveryExcept = deliveryException;   
            }
            if(node.getName() == 'Timestamp' && node.getParent().getName() == 'DeliveryException'){
              
                 if(node.getText().trim() !=null){deliveryException.timeStamp = node.getText().trim();} 
            }
            if(node.getName() == 'Notes' && node.getParent().getName() == 'DeliveryException'){
               deliveryException = new  NGUtilityClasses.DeliveryExcept();
                 if(node.getText().trim() !=null){deliveryException.notes = node.getText().trim();} 
            }
            if(node.getName() == 'Warehouse'){ 
             	warehouse = new NGUtilityClasses.Warehouse();
            	warehouse.id =node.getAttributeValue(node.getAttributeKeyAt(0), node.getAttributeKeyNsAt(0));
          	    ShipmentResponse.aWarehouse = warehouse;
            }
            if(node.getName() == 'Name' && node.getParent().getName() == 'Warehouse'){
                if(node.getText().trim() !=null){warehouse.name =node.getText().trim(); }
            }
             if(node.getName() == 'Address' && node.getParent().getName() == 'Warehouse'){
                if(node.getText().trim() !=null){warehouse.address =node.getText().trim(); }
            }
             if(node.getName() == 'City' && node.getParent().getName() == 'Warehouse'){
                if(node.getText().trim() !=null){warehouse.city =node.getText().trim(); }
            }
             if(node.getName() == 'State' && node.getParent().getName() == 'Warehouse'){
                if(node.getText().trim() !=null){warehouse.state =node.getText().trim(); }
            }
             if(node.getName() == 'PostalCode' && node.getParent().getName() == 'Warehouse'){
                if(node.getText().trim() !=null){warehouse.postalCode =node.getText().trim(); }
            }
             if(node.getName() == 'Country' && node.getParent().getName() == 'Warehouse'){
                if(node.getText().trim() !=null){warehouse.country =node.getText().trim(); }
            }
            if(node.getName() =='ShipMethod'){ if(node.getText().trim() !=null){ShipmentResponse.shipMethod = node.getText().trim();}}
            if(node.getName() =='ShipMethodCode'){ if(node.getText().trim() !=null){ShipmentResponse.shipMethodCode = node.getText().trim();}}
            if(node.getName() =='Tracking'){ if(node.getText().trim() !=null){ShipmentResponse.tracking = node.getText().trim();}}
            if(node.getName() =='TrackingUrl'){ if(node.getText().trim() !=null){ShipmentResponse.trackingUrl = node.getText().trim();}}
            if(node.getName() =='Weight' && node.getParent().getName() == 'Shipment'){ if(node.getText().trim() !=null){ShipmentResponse.weight = node.getText().trim(); }}
            if(node.getName() =='Postage'){ if(node.getText().trim() !=null){ShipmentResponse.postage = node.getText().trim();}}
            if(node.getName() =='GiftWrap'){if(node.getText().trim() !=null){ShipmentResponse.giftwrap = Boolean.valueOf(node.getText().trim());}}
            
           
            /*if(node.getName() == 'Items' && node.getParent().getParent().getName() == 'Shipment'){ 
                 ShipmentResponse.items = new List<NGUtilityCLasses.Item>();   
            }*/
            if(node.getName() == 'SKU' && node.getParent().getParent().getParent().getName() == 'Shipment'){
                if(node.getText().trim() !=null){ itemInfo.sku = node.getText().trim(); }
                system.debug('<< SKU>> '+ itemInfo.sku+' << ORDER ID >> '+ShipmentResponse.orderID);
            }
            if(node.getName() == 'UPC' && node.getParent().getParent().getParent().getName() == 'Shipment'){
                if(node.getText().trim() !=null){ itemInfo.upc = node.getText().trim(); }
                 system.debug('<< UPC>> '+ itemInfo.UPC+' << ORDER ID >> '+ShipmentResponse.orderID);
            }
            if(node.getName() == 'Description' && node.getParent().getParent().getParent().getName() == 'Shipment'){
                if(node.getText().trim() !=null){ itemInfo.description = node.getText().trim(); }
                 system.debug('<< DESCRIPTION >> '+ itemInfo.description+' << ORDER ID >> '+ShipmentResponse.orderID);
            }
            if(node.getName() == 'Lot' && node.getParent().getParent().getParent().getName() == 'Shipment'){
                if(node.getText().trim() !=null){ itemInfo.lot = node.getText().trim(); }
                 system.debug('<< LOT >> '+ itemInfo.lot+' << ORDER ID >> '+ShipmentResponse.orderID);
            }
            if(node.getName() == 'Qty' && node.getParent().getParent().getParent().getName() == 'Shipment'){
                if(node.getText().trim() !=null){ itemInfo.qty = Integer.valueOf(node.getText().trim()); }	
                system.debug('<< QTY>> '+ itemInfo.qty+' << ORDER ID >> '+ShipmentResponse.orderID);
            }
            if(node.getName() == 'Item' && node.getParent().getParent().getName() == 'Shipment'){
                itemInfo = new NGUtilityClasses.Item();
                ShipmentResponse.items=  new List<NGUtilityClasses.Item>();
               	itemInfo.id = node.getAttributeValue(node.getAttributeKeyAt(0), node.getAttributeKeyNsAt(0));
               	ShipmentResponse.items.add(itemInfo);
                
            }
            if(node.getName() == 'Items' && node.getParent().getParent().getName() == 'Shipment'){
                for(Dom.XMLNode child: node.getChildElements()){
		 			parseXML(child);
                 	system.debug('<< ITEMS >> '+node.getParent().getName());
            	 }
            }
            
                
               
           
            //===== Recursive loop ========
    		for (Dom.XMLNode child: node.getChildElements()) {
            	parseXML(child);
    		}
  		}
       
  	}//Method ParseXML

}

 
Alain CabonAlain Cabon
The recursive way is the only standard alternative offered in Apex but it is ... extremely verbose (more code, more bugs and more difficult to read)

You can get the items directly with just one short XPath expression. 

I am using a lot XQuery and my favorite tool is BaseX (German tool in java) but that is not possible in Apex.

We never use the recursive solution as far as possible because it is far too verbose.

I got the four items without problem.

The other problem with the recursive method is to verify the relative position all the time (parent).

User-added image

By the way there is an error here:

if(node.getName() == 'Items' && node.getParent().getParent().getName() == 'Shipment'){

XPath expression : /Shipment/Items/Item   ( the parent of items is direct )

It is a common error whitout using XPath.
Alain CabonAlain Cabon

if(node.getName() == 'Items' && node.getParent().getName() == 'Shipment'){

... should be sufficient.
Tony Williams 9Tony Williams 9
THanks Alain I will try the update. Good catch.
Tony Williams 9Tony Williams 9
Alain I tried using the code and it didn;t work for me. I'm passing in the xmnl string that we have been discussing b ut the items array doesn;t get loaded at all.
Alain CabonAlain Cabon
Salesforce is undergoing maintenance.  I am playing with free developer orgs and cannot do any test now.

You have two loops for the recursions but that is not the problem anymore given that there is an error for the first loop.

I tried the XPath alternative and that works for me.

All the needed code is below (don't parse with doc.load() anymore).
XPath xp = new XPath(xml);
Dom.XmlNode[] items = xp.find('/Shipment/Items/Item');

for (Dom.XmlNode item : items) {
    String item_id = item.getAttribute('id',null);   
    String item_sku = xp.getText(item, '', './SKU');
    String item_description = xp.getText(item, '', './Description');  
    system.debug('item:' + item_id + ' = ' + item_sku + ' = ' + item_description);
}
What is your XML text now?

 
Alain CabonAlain Cabon
Your code works so the problem is your XML file with an error perhaps (wrong tags?)


User-added image
Just copy/paste the code below in an anonymous window of a free developer org.
String xml = '<Shipment id="103052074"> \n' +
'    <ClientName>Awana</ClientName> \n' +
'    <OrderID>01061767</OrderID> \n' +
'    <PurchaseOrder /> \n' +
'    <Name>SILVIA GIBSON</Name> \n' +
'    <FirstName>SILVIA</FirstName> \n' +
'    <LastName>GIBSON</LastName> \n' +
'    <Company /> \n' +
'    <Address1>11900 TRADITION LN NE </Address1> \n' +
'    <Address2 /> \n' +
'    <City>ALBUQUERQUE</City> \n' +
'    <State>NM</State> \n' +
'    <PostalCode>87111-8287</PostalCode> \n' +
'    <Country>UNITED STATES</Country> \n' +
'    <Email>silviagibson@mailinator.com</Email> \n' +
'    <Phone /> \n' +
'    <OrderTimestamp>2019-01-18T00:00:00</OrderTimestamp> \n' +
'    <ReceivedTimestamp>2019-01-18T13:59:26.007</ReceivedTimestamp> \n' +
'    <ShipmentStatus>SHIPPED</ShipmentStatus> \n' +
'    <OrderType>Consumer</OrderType> \n' +
'    <ShippedDate>2019-01-18T14:16:37.550</ShippedDate> \n' +
'    <ExpectedDeliveryDate>2019-01-18T00:00:00</ExpectedDeliveryDate> <DeliveredTimestamp /> <DeliveryException />             \n' +
'    <Warehouse id="160"> \n' +
'       <Name>Greenwood, IN</Name> \n' +
'       <Address>1415 Collins Rd.</Address> \n' +
'       <City>Greenwood</City> \n' +
'       <State>IN</State> \n' +
'       <PostalCode>46143</PostalCode> \n' +
'       <Country>US</Country> \n' +
'    </Warehouse> \n' +
'    <ShipMethod>Newgistics Parcel Select</ShipMethod> \n' +
'    <ShipMethodCode>NGSPS</ShipMethodCode> \n' +
'    <Tracking>9200000000000629213249</Tracking>                  <TrackingUrl>http://shipment.co/tracking/2817/9200000000000629213249</TrackingUrl> \n' +
'     <Weight>4.000000</Weight> \n' +
'     <Postage /> \n' +
'     <GiftWrap>false</GiftWrap> \n' +
'     <CustomFields> \n' +
'         <BillingAddress1>1620 N Penny Ln</BillingAddress1> \n' +
'         <BillingCity>Schaumburg</BillingCity> \n' +
'         <BillingCompany>Cherry Hills Community Church</BillingCompany> \n' +
'         <BillingCountry>United States</BillingCountry> \n' +
'         <BillingEmail>silviagibson@mailinator.com</BillingEmail> \n' +
'         <BillingFirstName>Heather</BillingFirstName> \n' +
'         <BillingLastName>Oliver</BillingLastName> \n' +
'         <BillingPhone>(866) 292-6227</BillingPhone> \n' +
'         <BillingState>IL</BillingState> \n' +
'          <BillingZip>60173</BillingZip> \n' +
'           <Shipping>17.87</Shipping> \n' +
'           <Total>190.52</Total> \n' +
'      </CustomFields> \n' +
'      <BackorderedItems /> \n' +
'      <Items> \n' +
'         <Item id="1807577"> \n' +
'               <SKU>94900</SKU> \n' +
'                <UPC /> \n' +
'                 <Description>Cubbies AppleSeed Handbook Music CD NIV</Description> \n' +
'                <Lot /> \n' +
'                <Qty>2</Qty> \n' +
'               <CustomFields /> \n' +
'               <AssemblyItems /> \n' +
'       </Item> \n' +
'      <Item id="1807606"> \n' +
'             <SKU>96543</SKU> \n' +
'             <UPC /> \n' +
'             <Description>Cubbies HoneyComb Teaching Plans NKJV</Description> \n' +
'             <Lot /> \n' +
'             <Qty>1</Qty> \n' +
'             <CustomFields />  \n' +
'             <AssemblyItems /> \n' +
'      </Item> \n' +
'      <Item id="1807670"> \n' +
'           <SKU>96918</SKU> \n' +
'           <UPC /> \n' +
'           <Description>Game Pin (4)</Description> \n' +
'           <Lot /> \n' +
'           <Qty>4</Qty> \n' +
'           <CustomFields /> \n' +
'           <AssemblyItems /> \n' +
'     </Item> \n' +
'        <Item id="1807691"> \n' +
'          <SKU>46421</SKU> \n' +
'          <UPC /> \n' +
'          <Description>Gray Blouse, Leader Size 4X</Description> <Lot /> \n' +
'         <Qty>3</Qty> <CustomFields /> \n' +
'          <AssemblyItems /> \n' +
'     </Item> \n' +
'  </Items> \n' +
'   <Package id="86892375"> \n' +
'      <TrackingNumber>9200000000000629213249</TrackingNumber>\n' +
'      <Weight>4.30507</Weight> \n' +
'      <BillableWeight>4.00000</BillableWeight> \n' +
'      <Height>7.00000</Height> \n' +
'      <Width>4.00000</Width>  \n' +
'      <Depth>6.00000</Depth> \n' +
'</Package>\n' +
'</Shipment> \n';
  
SearchShipmentRequest( xml);
    
 public void SearchShipmentRequest(String xml){
         // Send the Search Shipment Request
           try
             {
           		// Read through the XML
                DOM.Document doc = new DOM.Document();
                 if(xml != '' && xml != null){
                	//system.debug('<< RESPONSE XML FROM NG >> '+xml);
                	doc.load(xml);
                	DOM.XmlNode rootNode = doc.getRootElement();   
          	  		parseXML(rootNode);                 
                 }else{
                     system.debug('<< No Data Was Read from NG Server>>');
                 }
             }catch(Exception ex)
             {
                 system.debug('There was an exception that occurred while processing the Shipment Repsonse '+ex.getMessage());
                 system.debug('<< Stack Trace >> '+ex.getStackTraceString()+' << Line Number >> '+ex.getLineNumber());
             }
 }
  void parseXML(DOM.XMLNode node) {
  		if (node.getNodeType() == DOM.XMLNodeType.ELEMENT) {     
            if(node.getName() == 'Item' && node.getParent().getParent().getName() == 'Shipment'){  
                system.debug('< id > ' + node.getAttribute('id',null));
            } else
            if(node.getName() == 'SKU' && node.getParent().getParent().getParent().getName() == 'Shipment'){                
                system.debug('   << SKU>> '+  node.getText());
            } else
            if(node.getName() == 'UPC' && node.getParent().getParent().getParent().getName() == 'Shipment'){             
                 system.debug('   << UPC>> '+ node.getText());
            } else
            if(node.getName() == 'Description' && node.getParent().getParent().getParent().getName() == 'Shipment'){            
                 system.debug('  << DESCRIPTION >> '+  node.getText());
            } 
    		for (Dom.XMLNode child: node.getChildElements()) {
            	parseXML(child);
    		}
  		}    
  	}
I keep all these working samples because that could be usefull for my own work later.
Tony Williams 9Tony Williams 9
Oh Ok, I tried it within the main class that used the instance SearchShipmentRequest( xml);  Just an FYI I'm also getting the string from a remote service that provies the xml response body but it still should be fine. Thanks.
Tony Williams 9Tony Williams 9
Also my issue is trying to maintain persistence.  It seem that sometimes when tetsing these I come up also with all nulls.  I Have gone the iterative route too. Tried using Iterations and got a time limit issue. - governor limits.
Tony Williams 9Tony Williams 9
HI Alian: BY hook or by crook I was able to solve it using recursion but mine may be a bitmore sloppy than yours but the one thing it seems to be doing correctly is persisting - none of the order items are dropping out. Thanks for your helpful ideas.
Florian Dardelet 7Florian Dardelet 7

Hello

Digging this old one as the solution is very clean and elegant. It works great in the examples and when I duplicate the actual response into a manual string but seems to break when used on an actual SOAP RS.

The issue seems to be from the second line below: 

XPath xp = new XPath(res.getBody()); 
Dom.XmlNode[] items = xp.find('/soap:Envelope/soap:Body/FareListDisplay/Fares/fareItem');

What do we need to do to convert the response output into a readable format for the XPath util?

Thanks