views:

157

answers:

1

Here is an example bit from the xml file:

<array>
    <dict>
        <key>Name</key>
        <string>Joe Smith</string>
        <key>Type</key>
        <string>Profile</string>
        <key>Role</key>
        <string>User</string>
        <key>Some Number</key>
        <integer>1</integer>
        <key>Some Boolean</key>
        <true/>
    </dict>
</array>

I have two separate goals. The first is to extract an array from the dictnode that would look like:

[Name] => Joe Smith
[Type] => Profile
[Role] => User
[Some Number] => 1
[Some Boolean] => true

It's not crucial that the boolean be included, so if that adds too much complexity, I'd rather just know how to deal with the others for now.

The second goal is to be able to select the value node (<string>, <integer>,etc) so that I can change the value. I know I would need to select it based on the text value of the preceding key element.

I think the following XPath should work:

//key[.=$keyname]/following-sibling[1]

But I'm not sure.

Basically, this whole system that Apple uses seems logical, but totally contrary to my understanding of how XML is supposed to work. If I ran the world, the original XML would look more like:

<dict type="array">
    <value key="Name" type="string">Joe Smith</value>
    <value key="Type" type="string">Profile</value>
    <value key="Role type="string">User</value>
    <value key="Some Number" type="integer">1</value>
    <value key="Some Boolean" type="boolean">true</value>
</dict>

But since it is fairly logical, I am wondering if I'm missing some obvious way of handling it.

A: 

Hi,

That xpath selector looks okay for that purpose to me. You'd probably want to check the value of the sibling you retrieve, to see if it's the tag you want to be changing (in the boolean case) or indeed the element's value.

In terms of extracting the data into an array, something along the lines of ...

$xml = new SimpleXMLElement($data);

$output = array();
$key = null;
$value = null;
foreach ($xml->dict->children() as $child) {
  if ($child->getName() == 'key') {
    $key = (string)$child;
  } elseif (!is_null($key)) {
    $childStr = (string)$child;
    $value = (empty($childStr) ? $child->getName() : $childStr);
  }

  if (!is_null($key) && !is_null($value)) {
    $output[$key] = $value;

    $key = null;
    $value = null;
  }
}

var_dump($output);

... should do what you're looking for from what I understand.

James

jstephenson