user2505513
user2505513

Reputation: 333

Xpath looping query

I have the following xml doc:

<shop id="123" name="xxx">
  <product id="123456">
    <name>Book</name>
    <price>9.99</price
  </product>
  <product id="789012">
    <name>Perfume</name>
    <price>12.99</price
  </product>
  <product id="345678">
    <name>T-Shirt</name>
    <price>9.99</price
  </product>
</shop>
<shop id="456" name="yyy">
  <product id="123456">
    <name>Book</name>
    <price>9.99</price
  </product>
</shop>

I have the following loop to gather the information for each product:

$data_feed = 'www.mydomain.com/xml/compression/gzip/';
$xml = simplexml_load_file("compress.zlib://$data_feed");

        foreach ($xml->xpath('//product') as $row) {
                        $id = $row["id"]; // product id eg. "123456"
                        $name = $row->name;
                        $price = $row->price;

        // update database etc.
        }

HOWEVER, I also want to gather the information for each product's parent shop ("id" and "name").

I can easily change my xpath to start from shop as opposed to product, but I'm unsure of the most efficient way to then construct an additional loop within my foreach to loop each indented product

Make sense?

Upvotes: 0

Views: 2072

Answers (2)

hakre
hakre

Reputation: 198237

Sure, makes sense, you want one iteration, not a nested product of iterations (albeit that won't cut you much, @michi showed already), which is possible as well:

foreach ($xml->xpath('//product') as $row) 
{
    $id       = $row["id"]; // product id eg. "123456"
    $name     = $row->name;
    $price    = $row->price;
    $shopId   = $row->xpath('../@id')[0];
    $shopName = $row->xpath('../@name')[0];

    // update database etc.
}

As this example shows, you can run xpath() on each element-node and the context-node is automatically set to the node itself, therefore the realtive path .. in xpath works to access the parent element (see as well: Access an element's parent with PHP's SimpleXML?). Of that then both attributes are read and then via PHP 5.4 array de-referencing the first (and only) attribute is accessed.

I hope this helps and shed some light how it works. Your question reminds me a bit of an earlier one where I suggested some kind of generic solution to these kind of problems:

Upvotes: 0

michi
michi

Reputation: 6625

I'd go without xpath and just use two nested foreach-loops:

$xml = simplexml_load_string($x); // assume XML in $x

foreach ($xml->shop as $shop) {
    echo "shop $shop[name], id $shop[id] <br />";
    foreach ($shop->product as $product) {
        echo "- $product->name (id $product[id]), $product->price <br />";
    }
}

see it working: http://codepad.viper-7.com/vFmGvY

BTW: your XML is broken, probably a typo. Each closing </price> is missing its last >.

Upvotes: 1

Related Questions