Получение пар ключ / значение из plist-стиля xml с использованием simplexml в php - PullRequest
3 голосов
/ 19 мая 2010

Вот пример бита из XML-файла:

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

У меня две отдельные цели. Первый - извлечь массив из узла dict, который будет выглядеть следующим образом:

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

Необязательно, чтобы логическое значение было включено, поэтому, если это добавляет слишком много сложности, я бы просто знал, как теперь обращаться с другими.

Вторая цель состоит в том, чтобы иметь возможность выбрать узел значения (<string>, <integer> и т. Д.), Чтобы я мог изменить значение. Я знаю, что мне нужно будет выбрать его на основе текстового значения предыдущего ключевого элемента.

Я думаю, что следующий XPath должен работать:

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

Но я не уверен.

По сути, вся эта система, которую использует Apple, кажется логичной, но полностью противоречит моему пониманию того, как должен работать XML. Если бы я управлял миром, исходный XML выглядел бы так:

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

Но так как это довольно логично, мне интересно, упускаю ли я какой-то очевидный способ справиться с этим.

Ответы [ 2 ]

3 голосов
/ 19 мая 2010

Для меня этот селектор xpath выглядит нормально. Возможно, вы захотите проверить значение полученного брата или сестры, чтобы увидеть, является ли это тег, который вы хотите изменить (в логическом случае), или действительно значением элемента.

С точки зрения извлечения данных в массив, что-то вроде ...

$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);

... должен делать то, что вы ищете из того, что я понимаю.

Джеймс

1 голос
/ 25 марта 2011

Вы можете использовать

/plist/dict/key[.='Name']/following-sibling::*[1]

, чтобы выбрать строковый узел "Джо Смит" и соответственно обновить его.

Мой PHP-код для обновления XML-файлов с использованием XPath выглядит следующим образом:

function updateNodesByXPath($xmlin, $expression, $value) {
    $dom = new DOMDocument();
    $dom->preserveWhiteSpace = true;
    $dom->formatOutput = false;
    $dom->loadXML($xmlin);
    $xpath = new DOMXPath($dom);
    $elements = $xpath->query($expression);
    foreach ($elements as $element) {
        $element->nodeValue = $value;
    }
    $xmlout = $dom->saveXML($dom, LIBXML_NOEMPTYTAG);

    // Add XML header when present before (DOMDocument::saveXML will remove it)
    if (strncasecmp($xmlin, '<?xml', 5)) {
        $xmlout = preg_replace('~<\?xml[^>]*>\s*~sm', '', $xmlout);
    }

    return $xmlout;
}
...