1

Update: Casting as an array does the trick. See this response, since I don't have enough clout to upvote :)

I started on this problem with many potential culprits, but after lots of diagnostics the problem is still there and no obvious answers remain.

I want to print the placename "Gaborone", which is located at the first tag under the first tag under the first tag of this API-loaded XML file. How can I parse this to return that content?

    <?php

      # load the XML file
      $test1 = (string)file_get_contents('http://www.afdb.org/fileadmin/uploads/afdb/Documents/Generic-Documents/IATIBotswanaData.xml');

      #throw it into simplexml for parsing      
      $xmlfile = simplexml_load_string($test1);

      #output the parsed text
      echo $xmlfile->iati-activity[0]->location[0]->gazetteer-entry;

    ?>

Which never fails to return this:

Parse error: syntax error, unexpected '[', expecting ',' or ';'

I've tried changing the syntax to avoid the hyphens in the tag names as such:

echo $xmlfile["iati-activity"][0]["location"][0]["gazetteer-entry"];

. . . but that returns complete nothingness; no error, no source.

I've also tried debugging based on these otherwise-helpful threads, but none of the solutions have worked. Is there an obvious error in my simplexml addressing?

Community
  • 1
  • 1
Bill Morris
  • 589
  • 8
  • 16

2 Answers2

1

I've tried changing the syntax to avoid the hyphens in the tag names as such: echo $xmlfile["iati-activity"][0]["location"][0]["gazetteer-entry"];

Your problem here is that, object native casting to an array isn't recursive, so that you did that for primary keys only. And yes, your guess is correct - you shouldn't deal with object properties when working with returned value of simplexml_load_string() because of the syntax issues. Instead, you should cast a returned value of it (stdclass) into an array recursively. You can use this function for that:

  function object2array($object) { 
    return json_decode(json_encode($object), true); 
  } 

The rest:

  // load the XML file
  $test1 = file_get_contents('http://www.afdb.org/fileadmin/uploads/afdb/Documents/Generic-Documents/IATIBotswanaData.xml');

  $xml = simplexml_load_string($test1);

  // Cast an object into array, that makes it much easier to work with
  $data = object2array($xml);

  $data = $data['iati-activity'][0]['location'][0]['gazetteer-entry']; // Works

  var_dump($data); // string(8) "Gaborone"
Yang
  • 8,580
  • 8
  • 33
  • 58
  • Perfect. Works like a charm and hitting it with 'echo' returns the result exactly as I was hoping for it. Thanks so much! – Bill Morris Sep 23 '13 at 03:57
  • Whoops - one more Q on this: does casting as an array remove my ability to use xpath? That had been working at least partially [in this example](https://gist.github.com/wboykinm/6666168#file-iati2geojson-L22) but now returns "Fatal Error: Call to a member function xpath() on a non-object" – Bill Morris Sep 23 '13 at 04:09
  • Xpath is meant to be used with XML stuff, while you're dealing with pure PHP-array now. You might want to implement a function that find elements without Xpath (use combination of `array_search()` and `foreach()`), I mean it's easy to replace Xpath with a function that collects that stuff and returns an array. – Yang Sep 23 '13 at 05:22
  • Zoiks. That seems to bork my plan of finding all instances of a particular tag and then collecting things up and down the tree from each. Is array_keys() the way to go for that sort of thing? – Bill Morris Sep 23 '13 at 16:38
0

I had a similar problem parsing XML using the simpleXML command until I did the following string replacements:

//$response contains the XML string
$response = str_replace(array("\n", "\r", "\t"), '', $response); //eliminate newlines, carriage returns and tabs
$response = trim(str_replace('"', "'", $response)); // turn double quotes into single quotes
$simpleXml = simplexml_load_string($response);
$json = json_decode(json_encode($simpleXml)); // an extra step I took so I got it into a nice object that is easy to parse and navigate

If that doesn't work, there's some talk over at PHP about CDATA not always being handled properly - PHP version dependent.

You could try this code prior to calling the simplexml_load_string function:

if(strpos($content, '<![CDATA[')) {
   function parseCDATA($data) {
      return htmlentities($data[1]);
   }
   $content = preg_replace_callback(
      '#<!\[CDATA\[(.*)\]\]>#',
      'parseCDATA',
      str_replace("\n", " ", $content)
   );
}

I've reread this, and I think your error is happening on your final line - try this:

echo $xmlfile->{'iati-activity'}[0]->location[0]->{'gazetteer-entry'};

Dave Hilditch
  • 5,299
  • 4
  • 27
  • 35
  • Thanks for the suggestion, but I'm afraid that didn't do it. The parse error is the same, and the addressing still doesn't return the indicated objects. – Bill Morris Sep 23 '13 at 02:43
  • I've added another possibility - since you're getting the error at '[' I guess it's CDATA causing the problem, but also check out this stackoverflow: http://stackoverflow.com/questions/14236607/xml-data-cleanup-before-calling-simplexml – Dave Hilditch Sep 23 '13 at 02:52
  • Is your error happening on the final line when you're accessing the elements rather than at parse of xml time? If so, solution added to answer above. – Dave Hilditch Sep 23 '13 at 02:57
  • Dave Just's answer above nailed it. Which means you were totally correct about casting as an array. Thanks! Also interesting to see the mustaches - is that an escape for the hyphen issue? – Bill Morris Sep 23 '13 at 03:56