在 php 中使用 simplexml 从 plist 样式的 xml 获取键/值对

发布于 2024-09-01 22:54:14 字数 1475 浏览 7 评论 0原文

以下是 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

包含布尔值并不重要,因此如果这增加了太多复杂性,我宁愿只知道如何处理其他人暂时。

第二个目标是能够选择值节点( 等),以便我可以更改值。我知道我需要根据前面的关键元素的文本值来选择它。

我认为以下 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>

但由于它相当合乎逻辑,我想知道我是否缺少一些明显的处理方法。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

成熟稳重的好男人 2024-09-08 22:54:14

在我看来,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);

我的理解,类似......的内容应该可以满足您的要求。

詹姆斯

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

捂风挽笑 2024-09-08 22:54:14

您可以使用

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

选择字符串节点“Joe Smith”并相应地更新它。

我使用 XPath 更新 XML 文件的 PHP 代码如下所示:

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

You can use

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

to select the string-node "Joe Smith" and update it accordingly.

My PHP code for updating XML files using XPath looks like this:

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文