【问题标题】:Converting XML tags to associative array将 XML 标记转换为关联数组
【发布时间】:2017-05-31 14:55:30
【问题描述】:

我有以下 curl 响应

<status>success</status><statusmsg>online</statusmsg><vmstat>online</vmstat><hostname>my.server.com</hostname><ipaddress>XXX.XXX.XXX.XXX</ipaddress>

这存储在$data

我试着把它转换成这样的数组

preg_match_all('/<(.*?)>([^<]+)</1>/i', $data, $match);
$result = array();
foreach ($match[1] as $x => $y)
{
$result[$y] = $match[2][$x];
}

但它不起作用

E_WARNING : type 2 -- preg_match_all(): Unknown modifier '1' -- at 第 3 行

$result 数组为空。

【问题讨论】:

  • 我对正则表达式一无所知,所以我做了什么,但我不知道是否可以:/&lt;(.*?)&gt;([^&lt;]+)&lt;\/.*&gt;/i如果有错误请纠正我
  • 使用正则表达式解析XML只会带来痛苦。使用像 SimpleXML 这样的 XML 解析器。

标签: php arrays regex xml preg-match-all


【解决方案1】:

使用正则表达式解析HTMLXML 不是好方法,而是使用DOMDocument

解决方案 1: Try this code snippet here

<?php
ini_set('display_errors', 1);

$string=<<<HTML
<status>success</status>
<statusmsg>online</statusmsg>
<vmstat>online</vmstat>
<hostname>my.server.com</hostname>
<ipaddress>XXX.XXX.XXX.XXX</ipaddress>
HTML;
;
$string="<root>".$string."</root>";
print_r((array)simplexml_load_string($string));

解决方案 2: Try this code snippet here

<?php
ini_set('display_errors', 1);

$string=<<<HTML
<status>success</status>
<statusmsg>online</statusmsg>
<vmstat>online</vmstat>
<hostname>my.server.com</hostname>
<ipaddress>XXX.XXX.XXX.XXX</ipaddress>
HTML;
;
$string="<root>".$string."</root>";
$domDocument = new DOMDocument();
$domDocument->loadXML($string);
$domXPath = new DOMXPath($domDocument);
$results = $domXPath->query("//root/*");
$data=array();
foreach($results as $result)
{
    if($result instanceof DOMElement)
    {
        $data[$result->tagName]=$result->nodeValue;
    }
}
print_r($data);

输出:

Array
(
    [status] => success
    [statusmsg] => online
    [vmstat] => online
    [hostname] => my.server.com
    [ipaddress] => XXX.XXX.XXX.XXX
)

【讨论】:

  • 这是我想要的输出。但是我必须使用 DOM .....?请注意,我无法控制收到的回复,因此只有我在问题中指定的内容没有 html 标签。
  • @Luka 正确的做法是DOM 而不是Regex。防止使用 regex 解析 XMLHTML ,如果您有多个属性、嵌套标签等,将来可能会卡住。
【解决方案2】:

您在重复组 1 附近的正则表达式中有错误。您必须在重复组之前添加 \。另外,为结束标记转义 /

它为您提供以下正则表达式:

/<(.*?)>([^<]+)<\/\1>/i

【讨论】:

  • 这很好用,简单明了,就像我喜欢的那样。输出很漂亮:Array ( [status] =&gt; success [statusmsg] =&gt; online [vmstat] =&gt; online [hostname] =&gt; aurora.myserver.com [ipaddress] =&gt; XXX.XXX.XXX.XXX )
  • 很高兴我能帮上忙。考虑将此答案标记为解决方案,以便其他用户也可以找到它。 :)
  • 伙计,你不要怀疑我没有立即点击 ✓ :) 所以不会让我再等一分钟。只要它允许我就会接受它
  • 请注意,您不需要循环来获取关联数组。你可以使用$result = array_combine($match[1], $match[2]);
【解决方案3】:

出于优化目的,请考虑急切的“修饰符”

/<([^>]+)>([^<]+)?<\/\1>/i

在我看来,捕获第一个元素很重要,因为您肯定会处理真正的 XML

<foo>bar</foo>

而不是

<foo>bar</superman>

【讨论】:

    【解决方案4】:

    假设您并不真正关心检查开始和结束标记是否匹配,这将提取每个标记内的数据并将其放入数组$result。 (从您的问题中不清楚您想要什么输出。)

    preg_match_all('/<(?:.*?)>([^<]+)<(?:.*?)>/i', $data, $result);
    

    请注意,使用(?: 而不仅仅是( 开始一个组仅意味着该组不会包含在结果中(这称为非捕获组) .

    编辑

    鉴于您想要一个关联数组,您可以执行以下操作:

    preg_match_all('/<(.*?)>([^<]+)<\/\1>/i', $data, $match);
    $result = array_combine($match[1], $match[2]);
    

    收集结果的循环是不必要的。

    【讨论】:

    • 在使用$result["status"]的例子中我想获取&lt;status&gt;标签的内容
    【解决方案5】:

    我认为其他任何基于正则表达式的解决方案都不会费心彻底消除这种模式。

    • 您的第一个捕获组应该使用否定字符类([^&gt;]+),您的第二个捕获组正确地执行此操作。

    • 无需在模式末尾使用i 修饰符,因为模式中没有字母字符。

    • 每个标签之间的文本可能为空,因此使用* 而不是+ 很重要。这将确保始终有一对匹配的元素供array_combine() 使用。

    • 如果preg_match_all() 返回false 结果,请务必在调用array_combine() 之前进行检查以避免收到警告消息。

    • 正如 Michael Mior 所说,array_combine() 是合并 [1][2] 匹配子数组的最直接/合适的方式。

    方法(Demo):

    $data='<empty></empty><status>success</status><statusmsg>online</statusmsg><vmstat>online</vmstat><hostname>my.server.com</hostname><ipaddress>XXX.XXX.XXX.XXX</ipaddress>';
    $result=preg_match_all('/<([^>]+)>([^<]*)<\/\1>/',$data,$out)?array_combine($out[1],$out[2]):[];
    var_export($result);
    

    注意:与 jarodev 的 141 步模式相比,我的模式只需 65 个“步骤”即可处理您的原始样本输入。请在您的项目中使用我更高效的模式。

    输出:

    array (
      'empty' => '',
      'status' => 'success',
      'statusmsg' => 'online',
      'vmstat' => 'online',
      'hostname' => 'my.server.com',
      'ipaddress' => 'XXX.XXX.XXX.XXX',
    )
    

    【讨论】:

      【解决方案6】:

      尝试使用simplexml_load_string函数。

      【讨论】:

      • 我专注于修复正则表达式。
      • @Luka 然后正确提问,而不是否决解决方案;)
      • @YaennuuH 我是投票反对的人,因为这不是解决方案。您只是提供了一个功能而没有解决问题。此外,XML 片段中没有根元素,因此 simplexml_load_string 无论如何都不会按原样工作。
      • 好的,所以对不起卢卡。 @Michael Mior 那么添加根元素而不是使用正则表达式是一种更好的解决方案;)我提供了一个指向 PHP 函数页面的链接,这样他就可以阅读并理解它是如何工作的。
      • @YaennuuH 请参阅有关 Meta 的此讨论,了解为什么应避免仅链接答案meta.stackexchange.com/questions/8231/…
      猜你喜欢
      • 2011-09-25
      • 2010-12-04
      • 2017-08-05
      • 2015-10-30
      • 1970-01-01
      • 1970-01-01
      • 2017-02-21
      • 2016-08-07
      • 1970-01-01
      相关资源
      最近更新 更多