4

I Use the following code to parse an XML file, with no problem:

 foreach ($xml->product as $products) {

 $title = $products->name; etc etc

However, due to structure of the XML I have to use xpath on one of the nodes I need to ensure it returns the correct data

 $actors = $xml->xpath("//property[name[. ='Actors']]/value");

 $actor = $actors[0];

This works great but it always returns the first record of the XML file where I need it to keep up with the loop, if that makes sense.

I tried the following but the same thing happens:

 $actors = $products->xpath("//property[name[. ='Actors']]/value");

Here is the xml in question, however my example above uses a node called name which has data Actors, swap that for Format and you have the same idea as there is a node below which is

<name>Format</name>


<properties>
 <group>
  <name>Product</name>
   <property>
    <id>48546006</id>
    <name>Product name</name>
    <value>JOLLY PHONICS (JOLLY PHONICS S.)</value>
   </property>
 </group>
 <group>
  <name>Product properties</name>
   <property>
    <id>43560296</id>
    <name>Product Title</name>
    <value>JOLLY PHONICS (JOLLY PHONICS S.)</value>
   </property>
   <property>
    <id>43560292</id>
     <name>Format</name>
     <value>DVD</value>
    </property>
   </group>
</properties>

and here is the full foreach loop i'm using (I've omitted some of it as you don't need to read multiple things that all work correctly as you'll see:

foreach ($xml->product as $products) { // AA

    $title = $products->name;

    $PRid = $products->id;

    $actors = $xml->xpath("//property[./name[.='Actors']]/value[next()]"); // this ok but repeats

$actors = $actors[0];

$genre = $xml->xpath("//property[name[. ='Genre']]/value"); 

$genre = $genre[0];

$prodcat = $products->{'category'};

    $addline = mysql_query("
    insert into dbname(
    blah blah
    )
        VALUES (
    blah blah
    ) ON DUPLICATE KEY UPDATE lowprice='$lowprice', highprice='$highprice'",$db);
    if(!$addline) { echo "cannot add to table here".mysql_error(); exit; } // debug

foreach ($xml->product->retailer as $retailer) { // BB

    this is another foreach loop but works perfectly

} // close BB
} // close AA

So, the problem is - I have nodes within the XML file that I need to extract which are always within the node called property, but, I can't simply use e.g. name[2] as they are sometimes in different places - therefore it is suggested I use xpath to get the data from the specific node I need as it's more precise - and the problem with that is that it works ok but for some reason will not simply get the data from the current node, however I try ./ or .//, it always returns the data from the first node.

Any ideas?

jamesmortensen
  • 33,636
  • 11
  • 99
  • 120
StudioTime
  • 22,603
  • 38
  • 120
  • 207

3 Answers3

0

I believe the following should work for you. Using ./ in xpath refers to the current node, rather than // as the root node:

$actors = $products->xpath("./property[name[. ='Actors']]/value");

It may need a little modification for your XML structure, which we can't see. But the key takeaway is using ./

UDPATE

Based on this question, try:

$actors = $products->xpath("./property/value[../name/text() = 'Actors']");
Community
  • 1
  • 1
Michael Berkowski
  • 267,341
  • 46
  • 444
  • 390
  • No joy I'm afraid, using $products->xpath as opposed to $xml->xpath produces nothing but tried ./ .// and leaving slashes off but still same thing – StudioTime Oct 07 '11 at 13:42
  • @DarrenSweeney Can you post some of your XML structure above? – Michael Berkowski Oct 07 '11 at 13:45
  • `./property/value[../name/text()='Actors']` is *way* too complicated. Better: `./property[name = 'Actors']/value` – Tomalak Oct 07 '11 at 15:07
  • Tried that,thanks, but it simply produces an empty Array i'm afraid – StudioTime Oct 07 '11 at 15:15
  • @Tomalak thanks... whatever i try with ./ or .// simply produces nothing – StudioTime Oct 07 '11 at 15:18
  • @Darren That's why I said: Post your PHP loop (stipped down to the smallest possible size) and an according XML fail that fails reproducibly. Letting people *guess* is not very productive, as you've seen. *Code samples* count, elaborate descriptions can only assist. – Tomalak Oct 07 '11 at 15:20
0

In xpath, starting with '//' means descendant-or-self, starting at the root. You might want to try adding a '.' to the beginning to start at the current node.

$string = file_get_contents('sampleFromPost.xml');
$xml = simplexml_load_string($string);

$groups = $xml->group;
foreach($groups as $group) {
    // Changed Actors to Product Title, since Actors doesn't exist in sample.

    $title = $group->xpath('.//property[name="Product Title"]/value');
    // -- or --
    $title = $group->xpath('.//property/value[../name="Product Title"]');

    // do something with the value
    var_dump($title);
}
rrehbein
  • 4,120
  • 1
  • 17
  • 23
  • No joy I'm afraid, using $products->xpath as opposed to $xml->xpath produces nothing but tried ./ .// and leaving slashes off but still same thing – StudioTime Oct 07 '11 at 13:43
0

As I suspected (before you posted your PHP code). You do not use relative paths in a loop body. Of course this always produces the same (i.e. the absolute) result.

You must refer to $product (not $xml) with your XPath and use a relative path from there, like this:

foreach ($xml->product as $product) { // AA
  $title   = $product->name;
  $PRid    = $product->id;
  $actors  = $product->xpath(".//property[name='Actors']/value");
  $genre   = $product->xpath(".//property[name='Genre']/value");
  $prodcat = $product->{'category'};

  $addline = mysql_query("
    insert into dbname(
      blah blah
    )
    VALUES (
      blah blah
    ) ON DUPLICATE KEY UPDATE lowprice='$lowprice', highprice='$highprice'", $db
  );

  if(!$addline) { 
    echo "cannot add to table here".mysql_error(); exit; // debug
  }

  foreach ($xml->product->retailer as $retailer) { // BB
    this is another foreach loop but works perfectly
  } // close BB
} // close AA

PS: Do you really want to run the BB loop within the AA loop (or do you actually mean to loop over $product->retailer here)?

Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • When i try to run the new line - $actors = $product->xpath(".//property[name='Actors']/value")[0]; - I get the following: Parse error: syntax error, unexpected '[' in /home/***/***/htdocs/PRFeed_Films.php on line 30 - I run another loop inside as there are approx 10-15 product reviews within each master node which i put into a seperate db and then join when i need them with the product id I create – StudioTime Oct 07 '11 at 16:55
  • @Darren OK then try the assignment of `[0]` on a separate line. PHP cannot do this in the same statement, obviously. – Tomalak Oct 07 '11 at 20:16