SimpleXML属性转换为数组

23

有没有更优雅的方法将SimpleXML属性转义成数组?

$result = $xml->xpath( $xpath );
$element = $result[ 0 ];
$attributes = (array) $element->attributes();
$attributes = $attributes[ '@attributes' ];
我不想通过循环来提取键/值对。我只需要将它转换为数组然后传递即可。我本以为attributes()默认就能做到,或者至少提供这个选项。但我甚至找不到上述解决方案的任何地方,我必须自己想出来。我是在过度复杂化问题还是什么? 编辑: 在确定访问@attributes数组是否安全之前,我仍然使用上述脚本。
5个回答

62

一种更优雅的方式; 它可以在不使用$attributes[ '@attributes' ]的情况下给您相同的结果:

$attributes = current($element->attributes());

2
绝对简单、紧凑且操作较少。 - abdulmanov.ilmir
4
这应该就是答案。 - kfriend
2
很好,谢谢!我通常会添加current(...)? : [],因为如果XML元素没有属性,current(...)返回false,而空数组(在我看来)更合适。 - Roman Hocke

12

不要直接读取'@attributes'属性,它是供内部使用的。无论如何,attributes()可以作为一个数组使用,而不需要“转换”为真正的数组。

例如:

<?php
$xml = '<xml><test><a a="b" r="x" q="v" /></test><b/></xml>';
$x = new SimpleXMLElement($xml);

$attr = $x->test[0]->a[0]->attributes();
echo $attr['a']; // "b"

如果你想要一个“真正”的数组,你就必须循环:

$attrArray = array();
$attr = $x->test[0]->a[0]->attributes();

foreach($attr as $key=>$val){
    $attrArray[(string)$key] = (string)$val;
}

2
是的,但这样做的问题在于它仍然将自己视为SimpleXML元素,因此您必须将$attr['a']强制转换为字符串才能正常工作。我将此数组传递给另一个类,该类不知道它应该是什么类型,只知道它需要是一个数组。 - mseancole
@showerhead:我不知道这样做是否更好,但我一直学习避免直接读取'@attributes'属性。 - gen_Eric
@showerhead:也许我错了,我不确定我从哪里得到的信息。如果它对你有用,我建议你使用它。文档中根本没有提到“@attributes”,既不使用也不不使用。 - gen_Eric
直接读取@attributes属性的缺点是什么? - PoX
接口Traversible,它是SimpleXmlElement实现的内容,不允许使用array_*()方法。这就是你需要真正的数组的地方。 - Im0rtality
显示剩余3条评论

4
你可以将整个xml文档转换为数组:
$array = json_decode(json_encode((array) simplexml_load_string("<response>{$xml}</response>")), true);

更多信息请参见:https://github.com/gaarf/XML-string-to-PHP-array。该链接与将XML字符串转换为PHP数组相关。

1
对于我来说,以下方法有效。
function xmlToArray(SimpleXMLElement $xml)
{
    $parser = function (SimpleXMLElement $xml, array $collection = []) use (&$parser) {
        $nodes = $xml->children();
        $attributes = $xml->attributes();

        if (0 !== count($attributes)) {
            foreach ($attributes as $attrName => $attrValue) {
                $collection['@attributes'][$attrName] = strval($attrValue);
            }
        }

        if (0 === $nodes->count()) {
            if($xml->attributes())
            {
                $collection['value'] = strval($xml);
            }
            else
            {
                $collection = strval($xml);
            }
            return $collection;
        }

        foreach ($nodes as $nodeName => $nodeValue) {
            if (count($nodeValue->xpath('../' . $nodeName)) < 2) {
                $collection[$nodeName] = $parser($nodeValue);
                continue;
            }

            $collection[$nodeName][] = $parser($nodeValue);
        }

        return $collection;
    };

    return [
        $xml->getName() => $parser($xml)
    ];
}

这还为我提供了所有属性,这是其他任何方法都没有给我的。

0

我认为你需要循环遍历。一旦读取了XML,你就可以将其放入数组中。

<?php
function objectsIntoArray($arrObjData, $arrSkipIndices = array())
{
$arrData = array();

// if input is object, convert into array
if (is_object($arrObjData)) {
    $arrObjData = get_object_vars($arrObjData);
}

if (is_array($arrObjData)) {
    foreach ($arrObjData as $index => $value) {
        if (is_object($value) || is_array($value)) {
            $value = objectsIntoArray($value, $arrSkipIndices); // recursive call
        }
        if (in_array($index, $arrSkipIndices)) {
            continue;
        }
        $arrData[$index] = $value;
    }
}
return $arrData;
}

$xmlStr = file_get_contents($xml_file);
$xmlObj = simplexml_load_string($xmlStr);
$arrXml = objectsIntoArray($xmlObj);

foreach($arrXml as $attr)
  foreach($attr as $key->$val){
 if($key == '@attributes') ....
}

1
什么是objectsIntoArray?另外,你不应该直接读取'@attributes',这就是->attributes()的作用。 - gen_Eric
抱歉,我从我的代码复制了一部分,漏掉了顶部部分,我已经编辑过了。 - PoX

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