将XML标记转换为关联数组

时间:2017-05-31 14:55:31

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

我有以下卷曲回复

<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:类型2 - preg_match_all():未知修饰符'1' - at   第3行

$result数组为空。

6 个答案:

答案 0 :(得分:3)

使用正则表达式解析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
)

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:1)

假设您并不真正关心检查起始和结束标记是否匹配,这将拉出每个标记内的数据并将其放入数组preg_match_all('/<(?:.*?)>([^<]+)<(?:.*?)>/i', $data, $result); 中。 (从你的问题中不清楚你想要什么输出。)

(?:

请注意,使用(而不仅仅preg_match_all('/<(.*?)>([^<]+)<\/\1>/i', $data, $match); $result = array_combine($match[1], $match[2]); 启动某个组只意味着该组不会包含在结果中(这称为非捕获 group)。

修改

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

tensorflow

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

答案 3 :(得分:1)

出于优化目的,请考虑急切的修饰符&#34;

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

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

<foo>bar</foo>

而不是

<foo>bar</superman>

答案 4 :(得分:0)

我没有看到任何其他基于正则表达式的解决方案都难以完全消除这种模式。

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

  • 您无需在模式的末尾使用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);
  

注意:我的模式将仅在65&#34;步骤&#34;处理您的原始样本输入。与jarodev的141步模式相比。请在项目中使用我更有效的模式。

输出:

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

答案 5 :(得分:-1)

尝试使用simplexml_load_string功能。