PHP 从随机嵌套、随机输出的 XML 中获取数组值,然后获取与第一个值搜索相关的关联值

PHP get array value from randomly nested, randomly outputted XML and then get associated values related to first value search

提问人:pwbset 提问时间:11/17/2023 最后编辑:pwbset 更新时间:11/17/2023 访问量:45

问:

呸。PHP假人在这里对不起。在这里搜索了又搜索,但搜索 foo 不够好。我觉得我在围绕一个答案跳舞,但array_filter、array_search、递归等。我只是在精神上没有掌握它,哈哈。

我从XML导出中获得了这个示例,其中XML的顺序不一致,格式也不好,嵌套级别有时甚至不同,等等,所以我无法根据它在导出中的具体位置来获取值,即使是假人我也可以这样做:

<INFRA>
<GUID>7C32C0A2-EF31-11E9-8128-4CCC6A98779E</GUID>
<ID>501</ID>
<NAME>P Cedar</NAME>
<TYP>36</TYP>
<TYPKRZ>50_IN_36_PARKPLATZ</TYPKRZ>
<TYPNAME>parking place</TYPNAME>
<STATUS>open</STATUS>
<STATUSWERT k="SONSTIGE" v="miscellaneous">1</STATUSWERT>
</INFRA>

在这种情况下,我需要查找/搜索唯一的字符串,无论它可能在导出中的哪个位置结束。然后,我需要为该特定变量分配一个变量,以便我可以对它进行一些运算。TIA!<NAME>P Cedar</NAME><STATUS><INFRA><NAME>

php xml 嵌套

评论

0赞 Barmar 11/17/2023
您是否正在使用 XML 解析器库?它应该有搜索标签的方法,然后找到封闭的标签,最后找到其中的标签,以便您可以更新它。<NAME><INFRA><STATUS>
1赞 TSCAmerica.com 11/17/2023
您可以使用 SimpleXML 扩展,它提供了一种处理 XML 文件的简单方法。

答:

0赞 Olivier 11/17/2023 #1

下面是一个基于 DOMXPath 的解决方案:

$xml = <<<XML
<ROOT>
    <NESTED>
        <INFRA>
            <GUID>7C32C0A2-EF31-11E9-8128-4CCC6A98779E</GUID>
            <ID>501</ID>
            <NAME>P Cedar</NAME>
            <TYP>36</TYP>
            <TYPKRZ>50_IN_36_PARKPLATZ</TYPKRZ>
            <TYPNAME>parking place</TYPNAME>
            <STATUS>open</STATUS>
            <STATUSWERT k="SONSTIGE" v="miscellaneous">1</STATUSWERT>
        </INFRA>
        <INFRA>
            <GUID>7C32C0A2-EF31-11E9-8128-4CCC6A98779E</GUID>
            <ID>501</ID>
            <NAME>D John</NAME>
            <TYP>36</TYP>
            <TYPKRZ>50_IN_36_PARKPLATZ</TYPKRZ>
            <TYPNAME>parking place</TYPNAME>
            <STATUS>closed</STATUS>
            <STATUSWERT k="SONSTIGE" v="miscellaneous">1</STATUSWERT>
        </INFRA>
    </NESTED>
</ROOT>
XML;

function getStatus($doc, $name)
{
    $xpath = new DOMXPath($doc);
    $entries = $xpath->query('//INFRA/NAME');
    foreach($entries as $entry)
    {
        if($entry->textContent == $name)
            return $entry->parentNode->getElementsByTagName('STATUS')[0]->textContent;
    }
    return null;    
}

$doc = new DOMDocument();
$doc->loadXML($xml);
echo getStatus($doc, 'P Cedar'); // open
echo getStatus($doc, 'D John'); // closed

出于性能原因,请考虑一次提取所有 NAME/STATUS 对(无需多次执行 XPath 查询)。

评论

0赞 pwbset 11/18/2023
谢谢!我已经进入了 DOM/XPath 兔子洞,事情很好地结合在一起。感谢您的意见/示例!总有新的东西要学!
0赞 ThW 11/17/2023 #2

用。Xpath 表达式允许复杂的条件和强制转换。因此,可以将逻辑直接放入表达式中:DOMXpath::evaluate()

  • 文档中的任何元素:INFRA//INFRA
  • ...带有子元素:NAME//INFRA[NAME]
  • ...等于:P Cedar//INFRA[NAME="P Cedar"]
  • ...孩子们:STATUS//INFRA[NAME="P Cedar"]/STATUS
  • ...作为字符串:string(//INFRA[NAME="P Cedar"]/STATUS)

Xpath 函数,例如获取节点列表并使用第一个节点的文本内容(或空字符串)。string()

$document = new DOMDocument();
$document->loadXML(getXML());
$xpath = new DOMXPath($document);

var_dump($xpath->evaluate('string(//INFRA[NAME = "P Cedar"]/STATUS)'));
var_dump($xpath->evaluate('string(//INFRA[NAME = "D John"]/STATUS)'));

function getXML() {
  return <<<XML
<ROOT>
    <NESTED>
        <INFRA>
            <GUID>7C32C0A2-EF31-11E9-8128-4CCC6A98779E</GUID>
            <ID>501</ID>
            <NAME>P Cedar</NAME>
            <TYP>36</TYP>
            <TYPKRZ>50_IN_36_PARKPLATZ</TYPKRZ>
            <TYPNAME>parking place</TYPNAME>
            <STATUS>open</STATUS>
            <STATUSWERT k="SONSTIGE" v="miscellaneous">1</STATUSWERT>
        </INFRA>
        <INFRA>
            <GUID>7C32C0A2-EF31-11E9-8128-4CCC6A98779E</GUID>
            <ID>501</ID>
            <NAME>D John</NAME>
            <TYP>36</TYP>
            <TYPKRZ>50_IN_36_PARKPLATZ</TYPKRZ>
            <TYPNAME>parking place</TYPNAME>
            <STATUS>closed</STATUS>
            <STATUSWERT k="SONSTIGE" v="miscellaneous">1</STATUSWERT>
        </INFRA>
    </NESTED>
</ROOT>
XML;
}

要获取所有名称,您需要迭代节点并将它们用作详细表达式的上下文(的第二个参数):STATUSDOMXpath::evaluate()

$document = new DOMDocument();
$document->loadXML(getXML());
$xpath = new DOMXPath($document);

$statusByName = array_reduce(
  iterator_to_array($xpath->evaluate('//INFRA')),
  static function (array $carry, \DOMNode $infra) use ($xpath) {
      $name = $xpath->evaluate('string(NAME)', $infra);
      $status = $xpath->evaluate('string(STATUS)', $infra);
      $carry[$name] = $status;
      return $carry;
  },
  []
);

var_dump($statusByName);