We help IT Professionals succeed at work.

XML Foreach

Robert Granlund
on
Medium Priority
592 Views
Last Modified: 2012-09-01
How would I parse and write a foreach statement for the following XML File:

<?xml version="1.0" encoding="UTF-8"?>
<notification-data-response xmlns="http://checkout.google.com/schema/2" serial-number="191d741b-b6e9-47f5-ae6a-3795494cd020">
  <notifications>
    <new-order-notification serial-number="552212673191311-00001-7">
      <buyer-billing-address>
        <address1></address1>
        <address2></address2>
        <phone></phone>
        <email>info@test.com</email>
        <contact-name>Robert </contact-name>
        <company-name></company-name>
        <fax></fax>
        <country-code>US</country-code>
        <city></city>
        <region></region>
        <postal-code>65401</postal-code>
      </buyer-billing-address>
      <timestamp>2012-08-03T21:50:02.222Z</timestamp>
      <google-order-number>552212673191311</google-order-number>
      <shopping-cart>
        <items>
          <item>
            <item-name>Cleveland Independents $25.00 Gift Card</item-name>
            <item-description></item-description>
            <unit-price currency="USD">25.0</unit-price>
            <quantity>5</quantity>
          </item>
        </items>
      </shopping-cart>
      <order-adjustment>
        <merchant-codes />
        <total-tax currency="USD">0.0</total-tax>
        <adjustment-total currency="USD">0.0</adjustment-total>
      </order-adjustment>
      <buyer-id>405269321627164</buyer-id>
      <buyer-shipping-address>
        <address1>825 Test</address1>
        <address2></address2>
        <phone></phone>
        <email>info@test.com</email>
        <contact-name>Robert</contact-name>
        <company-name></company-name>
        <fax></fax>
        <country-code>US</country-code>
        <city></city>
        <region></region>
        <postal-code></postal-code>
      </buyer-shipping-address>
      <buyer-marketing-preferences>
        <email-allowed>true</email-allowed>
      </buyer-marketing-preferences>
      <order-total currency="USD">125.0</order-total>
      <fulfillment-order-state>NEW</fulfillment-order-state>
      <financial-order-state>REVIEWING</financial-order-state>
    </new-order-notification>

Open in new window

Comment
Watch Question

Most Valuable Expert 2011
Author of the Year 2014

Commented:
This does not appear to be valid XML.
Most Valuable Expert 2011
Author of the Year 2014

Commented:
Please have a look at http://www.laprbass.com/RAY_temp_rgranlund.php

I added a couple of lines to make it work.  See lines 63, 64.

<?php // RAY_temp_rgranlund.php
error_reporting(E_ALL);
echo '<pre>';


// FROM THE POST AT EE
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<notification-data-response xmlns="http://checkout.google.com/schema/2" serial-number="191d741b-b6e9-47f5-ae6a-3795494cd020">
  <notifications>
    <new-order-notification serial-number="552212673191311-00001-7">
      <buyer-billing-address>
        <address1></address1>
        <address2></address2>
        <phone></phone>
        <email>info@test.com</email>
        <contact-name>Robert </contact-name>
        <company-name></company-name>
        <fax></fax>
        <country-code>US</country-code>
        <city></city>
        <region></region>
        <postal-code>65401</postal-code>
      </buyer-billing-address>
      <timestamp>2012-08-03T21:50:02.222Z</timestamp>
      <google-order-number>552212673191311</google-order-number>
      <shopping-cart>
        <items>
          <item>
            <item-name>Cleveland Independents $25.00 Gift Card</item-name>
            <item-description></item-description>
            <unit-price currency="USD">25.0</unit-price>
            <quantity>5</quantity>
          </item>
        </items>
      </shopping-cart>
      <order-adjustment>
        <merchant-codes />
        <total-tax currency="USD">0.0</total-tax>
        <adjustment-total currency="USD">0.0</adjustment-total>
      </order-adjustment>
      <buyer-id>405269321627164</buyer-id>
      <buyer-shipping-address>
        <address1>825 Test</address1>
        <address2></address2>
        <phone></phone>
        <email>info@test.com</email>
        <contact-name>Robert</contact-name>
        <company-name></company-name>
        <fax></fax>
        <country-code>US</country-code>
        <city></city>
        <region></region>
        <postal-code></postal-code>
      </buyer-shipping-address>
      <buyer-marketing-preferences>
        <email-allowed>true</email-allowed>
      </buyer-marketing-preferences>
      <order-total currency="USD">125.0</order-total>
      <fulfillment-order-state>NEW</fulfillment-order-state>
      <financial-order-state>REVIEWING</financial-order-state>
    </new-order-notification>
    </notifications>
    </notification-data-response>
XML;

$obj = SimpleXML_Load_String($xml);
var_dump($obj);

Open in new window

Author

Commented:
@ray... thank you for the assistance.  What I'm really having a question/issue with is how do I parse out the return into a "foreach" statement?  I only need to know how to start it.
Most Valuable Expert 2011
Author of the Year 2014

Commented:
how do I parse out the return into a "foreach" statement?
PHP foreach() is an iterator.  It is used to traverse an array or object and access the elements within the larger data structure.  In order to use it effectively you need to know what elements you're interested in getting.
http://en.wikipedia.org/wiki/Iterator

Iterators are not needed in PHP if you have only one element, and it appears from the XML that we have only one of notifications, new-order-notification, shopping-cart, items, item, etc., so a foreach() example may not mean very much with this test data set.  Nevertheless, you can see the moving parts starting at line 70.  

Note the awkward notation with the squiggly braces and quotes.  This is required because the XML tags have hyphens (dashes, minus-signs) in the name.  The hyphen is usually a subtraction operator and does not make sense as part of a tag name.  You've got to wonder what Google was thinking when they set this up!  It would have made a lot more sense to me if they had used the underscore; it has no meaning in arithmetic and is commonly used as a separator_character in longer multi_word names.

<?php // RAY_temp_rgranlund.php
error_reporting(E_ALL);
echo '<pre>';


// FROM THE POST AT EE
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<notification-data-response xmlns="http://checkout.google.com/schema/2" serial-number="191d741b-b6e9-47f5-ae6a-3795494cd020">
  <notifications>
    <new-order-notification serial-number="552212673191311-00001-7">
      <buyer-billing-address>
        <address1></address1>
        <address2></address2>
        <phone></phone>
        <email>info@test.com</email>
        <contact-name>Robert </contact-name>
        <company-name></company-name>
        <fax></fax>
        <country-code>US</country-code>
        <city></city>
        <region></region>
        <postal-code>65401</postal-code>
      </buyer-billing-address>
      <timestamp>2012-08-03T21:50:02.222Z</timestamp>
      <google-order-number>552212673191311</google-order-number>
      <shopping-cart>
        <items>
          <item>
            <item-name>Cleveland Independents $25.00 Gift Card</item-name>
            <item-description></item-description>
            <unit-price currency="USD">25.0</unit-price>
            <quantity>5</quantity>
          </item>
        </items>
      </shopping-cart>
      <order-adjustment>
        <merchant-codes />
        <total-tax currency="USD">0.0</total-tax>
        <adjustment-total currency="USD">0.0</adjustment-total>
      </order-adjustment>
      <buyer-id>405269321627164</buyer-id>
      <buyer-shipping-address>
        <address1>825 Test</address1>
        <address2></address2>
        <phone></phone>
        <email>info@test.com</email>
        <contact-name>Robert</contact-name>
        <company-name></company-name>
        <fax></fax>
        <country-code>US</country-code>
        <city></city>
        <region></region>
        <postal-code></postal-code>
      </buyer-shipping-address>
      <buyer-marketing-preferences>
        <email-allowed>true</email-allowed>
      </buyer-marketing-preferences>
      <order-total currency="USD">125.0</order-total>
      <fulfillment-order-state>NEW</fulfillment-order-state>
      <financial-order-state>REVIEWING</financial-order-state>
    </new-order-notification>
  </notifications>
</notification-data-response>
XML;

// MAKE AN OBJECT
$obj = SimpleXML_Load_String($xml);

// USE ITERATORS TO ACCESS THE PROPERTIES OF THE OBJECT
foreach ($obj->notifications as $n)
{
    $s = $n->{'new-order-notification'}['serial-number'];
    echo PHP_EOL . $s;

    foreach ($n->{'new-order-notification'}->{'buyer-billing-address'} as $b)
    {
        echo PHP_EOL . $b->email;
        echo PHP_EOL . $b->{'contact-name'};
    }
}

Open in new window

HTH, ~Ray

Author

Commented:
@Ray.  Thank you for your continued help.  I'm finding the whole google polling API tedious but worth the learning curve.  The one issue that has come up is the following: "new Order Notifications" comes up one and the every order is specified by its own serial number.  So when I run the foreach code you have supplied, it returns one order.

So one line 76 it should be like:
foreach ($n->{'serial-number'}->{'buyer-shipping-address'} as $b)

Open in new window


 even though that wont work. Ideas?
Most Valuable Expert 2011
Author of the Year 2014

Commented:
So when I run the foreach code you have supplied, it returns one order.
Right, there is only one order in the test data, AFAIK.  Do you have some new test data that would show multiple orders?

Author

Commented:
@Ray

<?php
$xmlb = <<<ENDREQ
<?xml version="1.0" encoding="UTF-8"?>
<notification-data-request xmlns="http://checkout.google.com/schema/2">
  <continue-token>CKbpmu2OJxCKr4iexu0fGA0</continue-token>
</notification-data-request>
ENDREQ;

$headerb = "Authorization: Basic " . base64_encode($credentials) . "\r\n"
. "Content-type: application/xml; charset=UTF-8'" . "\r\n"
. "Accept: application/xml; charset=UTF-8" . "\r\n"
;

$fileb = curl_postb('https://202722291950428:wQqfjNYNXX2aUbZJx5Pu0A@sandbox.google.com/checkout/api/checkout/v2/reports/Merchant/202722291950428/', $xmlb, $headerb);
//var_dump($fileb);

function curl_postb($url, $post_string=NULL, $header=NULL, $timeout=4, $error_report=TRUE)
{
    // PREPARE THE CURL CALL
    $curl = curl_init();
    curl_setopt( $curl, CURLOPT_URL,            $url         );
    curl_setopt( $curl, CURLOPT_HEADER,         $header      );
    curl_setopt( $curl, CURLOPT_POST,           TRUE         );
    curl_setopt( $curl, CURLOPT_POSTFIELDS,     $post_string );
    curl_setopt( $curl, CURLOPT_TIMEOUT,        $timeout     );
    curl_setopt( $curl, CURLOPT_RETURNTRANSFER, TRUE         );

    // EXECUTE THE CURL CALL
    $htm = curl_exec($curl);
    $err = curl_errno($curl);
    $inf = curl_getinfo($curl);

    // ON FAILURE
    if (!$htm)
    {
        // PROCESS ERRORS HERE
        if ($error_report)
        {
            echo "CURL FAIL: $url TIMEOUT=$timeout, CURL_ERRNO=$err";
            echo "<pre>\n";
            var_dump($inf);
            echo "</pre>\n";
        }
        curl_close($curl);
        return FALSE;
    }

    // ON SUCCESS
    curl_close($curl);
    return $htm;
}

?>

<?php
$obj = SimpleXML_Load_String($fileb);
 
// ACTIVATE THIS TO VISUALIZE THE OBJECT
echo "<pre>\n";
var_dump($obj);
echo "</pre>\n";

// USE ITERATORS TO ACCESS THE PROPERTIES OF THE OBJECT
foreach ($obj->notifications as $n)
{
    $s = $n->{'new-order-notification'}['serial-number'];
    echo PHP_EOL . $s;

    foreach ($n->{'new-order-notification'}->{'buyer-billing-address'} as $b)
    {
        echo PHP_EOL . $b->email;
        echo PHP_EOL . $b->{'contact-name'};
    }
}
?>

Open in new window

Author

Commented:
The end result here is that I want to keep a bunch of the Google Order info in my own DB instead of going to Google all the time.  The second reason and the reason this has come about, is that google has no way of sending out a customized email once the order is finished.
Most Valuable Expert 2011
Author of the Year 2014
Commented:
See: http://www.laprbass.com/RAY_temp_rgranlund.php

<?php // RAY_temp_rgranlund.php
error_reporting(E_ALL);
echo "<pre>\n";

$xmlb = <<<ENDREQ
<?xml version="1.0" encoding="UTF-8"?>
<notification-data-request xmlns="http://checkout.google.com/schema/2">
  <continue-token>CKbpmu2OJxCKr4iexu0fGA0</continue-token>
</notification-data-request>
ENDREQ;

$headerb = "Authorization: Basic " . "\r\n"
. "Content-type: application/xml; charset=UTF-8'" . "\r\n"
. "Accept: application/xml; charset=UTF-8" . "\r\n"
;

$fileb = curl_postb('https://202722291950428:wQqfjNYNXX2aUbZJx5Pu0A@sandbox.google.com/checkout/api/checkout/v2/reports/Merchant/202722291950428/', $xmlb, $headerb);
//var_dump($fileb);

function curl_postb($url, $post_string=NULL, $header=NULL, $timeout=4, $error_report=TRUE)
{
    // PREPARE THE CURL CALL
    $curl = curl_init();
    curl_setopt( $curl, CURLOPT_URL,            $url         );
    curl_setopt( $curl, CURLOPT_HEADER,         $header      );
    curl_setopt( $curl, CURLOPT_POST,           TRUE         );
    curl_setopt( $curl, CURLOPT_POSTFIELDS,     $post_string );
    curl_setopt( $curl, CURLOPT_TIMEOUT,        $timeout     );
    curl_setopt( $curl, CURLOPT_RETURNTRANSFER, TRUE         );

    // EXECUTE THE CURL CALL
    $htm = curl_exec($curl);
    $err = curl_errno($curl);
    $inf = curl_getinfo($curl);

    // ON FAILURE
    if (!$htm)
    {
        // PROCESS ERRORS HERE
        if ($error_report)
        {
            echo "CURL FAIL: $url TIMEOUT=$timeout, CURL_ERRNO=$err";
            echo "<pre>\n";
            var_dump($inf);
            echo "</pre>\n";
        }
        curl_close($curl);
        return FALSE;
    }

    // ON SUCCESS
    curl_close($curl);
    return $htm;
}

?>

<?php
$obj = SimpleXML_Load_String($fileb);

// ACTIVATE THIS TO VISUALIZE THE OBJECT
// print_r($obj);

// USE ITERATORS TO ACCESS THE PROPERTIES OF THE OBJECT
foreach ($obj->notifications as $n)
{
    $s = $n->{'new-order-notification'}['serial-number'];
    echo PHP_EOL . $s;
    echo PHP_EOL;

    foreach ($n->{'new-order-notification'} as $o)
    {
        echo PHP_EOL . ($o->{'buyer-billing-address'}->{'contact-name'});
        foreach ($o->{'shopping-cart'}->items->item as $i)
        {
            echo PHP_EOL . $i->{'item-name'};
            echo $i->{'item-price'};
        }
        echo PHP_EOL;
    }
}

Open in new window

Author

Commented:
OK, this is awesome.  I will continue forward and find out how I can break it!... again...

Explore More ContentExplore courses, solutions, and other research materials related to this topic.