开发者

xpath inside a foreach loop repeating same result

开发者 https://www.devze.com 2023-04-11 16:40 出处:网络
I Use the following code to parse an XML file, with no problem: foreach ($xml->product as $products) {

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>
    &开发者_JAVA技巧lt;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?


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)?


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']");


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);
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号