XML转换成数组?[PHP]

8

我一直在尝试将一个XML转换回数组,但遇到了问题...如果每个XML都遵循相同的格式,那将会很简单,但实际上每个XML都不同,只有<Formula>, formulaname和movespeed这个标签是例外。

<Formula>
<formulaname>Basic</formulaname>
<movespeed>1</movespeed>
<str>4</str>
<dex>3</dex>
<int>1</int>
<will>2</will>
</Formula>

或者

<Formula>
<formulaname>Basic</formulaname>
<movespeed>1</movespeed>
<box>4</box>
<chicken>3</chicken>
<ducks>1</ducks>
<cereal>2</cereal>
</Formula>

我尝试过以下方法:

$xml = simplexml_load_file("test.xml");
print_r($xml);

这实际上会打印一些东西,但我无法继续甚至echo它。

foreach($xml->text as $string) { 
  print_r($string);
  echo 'attributes: '. $string->attributes() .'<br />';
}

没有起作用,最初是为了处理字符串,但它们都不是字符串...

foreach ($xml->Formula as $element) {
  foreach($element as $key => $val) {
   echo "{$key}: {$val}";
  }

这也行不通,我需要像这样的东西才能使用来自array的值,而不知道值被称为什么。


你的XML文件有根标签吗?还是只是一堆公式标签? - Ja͢ck
你能否不使用XML?如果可以改用JSON,那么简单的 json_decode($json, TRUE) 函数即可满足你的需求。 - FtDRbwLXw6
属性是一个对象,将其强制转换为数组 $attributes = $string->attributes(); $attributes = (array) $attributes; 然后你就可以获取你想要的任何东西了。 - wesside
XML基本上如所显示的那样,但是很遗憾我被锁定使用XML。 $attributes = $string->attributes(); $attributes = (array); echo 'attributes: '. $attributes .'<br />'; 出现错误。 - Ginzo Milani
建议在此处阅读:http://php.net/manual/en/class.simplexmliterator.php -- 评论中有几个XML2Array示例函数。 - Spudley
4个回答

20

这是你最好的选择,它应该会消除所有的SimpleXMLElement对象,而只提供数组:

$xml = simplexml_load_file("test.xml");
$xml_array = unserialize(serialize(json_decode(json_encode((array) $xml), 1)));
print_r($xml_array);

使得这两者不同:


包含SimpleXMLElement对象的数组


和这个:


所有的数组 - 不包括SimpleXMLElement对象


希望这有所帮助... :)


1
在短变体中有效的代码:$xml_array = json_decode(json_encode((array) $firmInfoXml), 1)。 - SergO
1
更简洁的写法:json_decode(json_encode($xml), 1);(无需强制转换) - Alain Tiemblo

9

使用 .children() 来访问节点的子元素,而不能通过在节点本身上使用 foreach 来访问子元素:

$s =<<<EOS
<root>
<Formula>
<formulaname>Basic</formulaname>
<movespeed>1</movespeed>
<box>4</box>
<chicken>3</chicken>
<ducks>1</ducks>
<cereal>2</cereal>
</Formula>
</root>
EOS;

$xml = simplexml_load_string($s);

foreach ($xml->Formula as $element) {
    foreach($element->children() as $key => $val) {
        echo "{$key}: {$val}";
    }
}

它没有输出任何东西 v.v - Ginzo Milani
@GinzoMilani 更新了我的答案,让它对我起作用了。 - Ja͢ck
这是我用作测试的xml,尽管每个xml的内容都不同。 - Ginzo Milani
@GinzoMilani - 你能否更详细地解释一下为什么这对你不起作用?据我所知,如果你将你的 XML 放在上面的代码中,它应该会输出子元素。+1 - halfer
@GinzoMilani 您的 XML 应该有一个根节点;如果没有,则可以跳过外部循环 :) - Ja͢ck

9

对于你的示例,这段代码就足够了:

$xml = simplexml_load_file('formula.xml');
$arr = (array) $xml;
var_dump($arr);

将您的 XML 放入数组中
formula.xml 包含您的 XML


3
只适用于一级目录(对于更深层次的目录,@jerdiggity的回答更好)。 - Alain Tiemblo

3

如果在同一个节点中存在CDATA和属性,使用上述方法将省略属性。

可以尝试使用以下方法:

function xml2array($xmlObject, $out = [])
{
    foreach($xmlObject->attributes() as $attr => $val)
        $out['@attributes'][$attr] = (string)$val;

    $has_childs = false;
    foreach($xmlObject as $index => $node)
    {
        $has_childs = true;
        $out[$index][] = xml2array($node);
    }
    if (!$has_childs && $val = (string)$xmlObject)
        $out['@value'] = $val;

    foreach ($out as $key => $vals)
    {
        if (is_array($vals) && count($vals) === 1 && array_key_exists(0, $vals))
            $out[$key] = $vals[0];
    }
    return $out;
}
$xml = simplexml_load_string($xml_string, 'SimpleXMLElement', LIBXML_NOCDATA);
$arr = xml2array($xml);

即使不需要(例如:当没有属性时),每个节点上都会添加一个无用的“@value”键,但是因为指出了在节点包含值时属性会丢失而获得+1。 - Alain Tiemblo
1
+1 你知道它是一个值而不是属性,所以它并不是无用的。如果你需要解析结果数组,在将其解释为属性值之前,你不需要检查节点是否具有属性。这应该是被接受的答案,因为问题是如何在PHP中将XML转换为数组(而不丢失数据)。 - lalengua

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接