从SimpleXMLObject到Array的递归转换

28

我需要递归地将 PHP SimpleXMLObject 转换成数组。问题是每个子元素也是PHP SimpleXMLElement。

这是否可行?

7个回答

77
json_decode(json_encode((array) simplexml_load_string($obj)), 1);

1
聪明!我从来没有想过要这样做。 - General Redneck
4
如果可能的话,我会给您100个赞。太棒了 :) - Arvind Bhardwaj
1
@AdamLibuša 是的,但你怎么在 PHP 数组中保存属性呢? - Jeff Puckett
说真的,这个答案怎么能被接受呢?对于最简单的测试用例都不起作用:$xml = ''; $array = json_decode(json_encode((array) simplexml_load_string($xml)), 1); var_dump($array); ?>``` `empty` 将会被转换为一个空数组而不是 `null`。 - Eric MORAND
还有一个很大的缺点,就是将所有内容都转换为字符串。但是当你有布尔值或整数时,它们都会被强制转换为字符串,这并不是最优的选择。 - Robert

6

我没有测试过这个方法,但它似乎可以解决问题:

function convertXmlObjToArr($obj, &$arr) 
{ 
    $children = $obj->children(); 
    foreach ($children as $elementName => $node) 
    { 
        $nextIdx = count($arr); 
        $arr[$nextIdx] = array(); 
        $arr[$nextIdx]['@name'] = strtolower((string)$elementName); 
        $arr[$nextIdx]['@attributes'] = array(); 
        $attributes = $node->attributes(); 
        foreach ($attributes as $attributeName => $attributeValue) 
        { 
            $attribName = strtolower(trim((string)$attributeName)); 
            $attribVal = trim((string)$attributeValue); 
            $arr[$nextIdx]['@attributes'][$attribName] = $attribVal; 
        } 
        $text = (string)$node; 
        $text = trim($text); 
        if (strlen($text) > 0) 
        { 
            $arr[$nextIdx]['@text'] = $text; 
        } 
        $arr[$nextIdx]['@children'] = array(); 
        convertXmlObjToArr($node, $arr[$nextIdx]['@children']); 
    } 
    return; 
} 

摘自http://www.codingforums.com/showthread.php?t=87283

以下是需要翻译的内容:

如何在PHP中检查是否存在某个类?

我该如何在PHP中检查某个类是否已经定义了呢?

有没有像Java中的Class.forName()这样的方法?

谢谢。


1
不确定为什么其他人会觉得这个“不起作用”,但它确实可以遍历所有子元素和属性。 - Kristen Waite

0

对于那些关心CDATA情况的人,

将@ajayi-oluwaseun-emmanuel的答案与this answer结合起来对我很有帮助:

$xml = simplexml_load_string($xml_str, 'SimpleXMLElement', LIBXML_NOCDATA);
$json = json_encode($xml);
$arr = json_decode($json,TRUE);

0

由于 CDATA、数组等方面的一些问题(请参见:SimpleXMLElement to PHP Array),我认为以下可能是最好的解决方案:

public function simpleXml2ArrayWithCDATASupport($xml)
{
    $array = (array)$xml;

    if (count($array) === 0) {
        return (string)$xml;
    }

    foreach ($array as $key => $value) {
        if (is_object($value) && strpos(get_class($value), 'SimpleXML') > -1) {
            $array[$key] = $this->simpleXml2ArrayWithCDATASupport($value);
        } else if (is_array($value)) {
            $array[$key] = $this->simpleXml2ArrayWithCDATASupport($value);
        } else {
            continue;
        }
    }

    return $array;
}

0

是可以的。这是一个递归函数,它打印出父元素的标签以及没有子元素的元素的标签和内容。您可以将其修改为构建一个数组:

foreach( $simpleXmlObject as $element )
{
    recurse( $element );
}

function recurse( $parent )
{
    echo '<' . $parent->getName() . '>' . "\n";    

    foreach( $parent->children() as $child )
    {
        if( count( $child->children() ) > 0 )
        {
            recurse( $child );
        }
        else
        {
           echo'<' . $child->getName() . '>';
           echo  iconv( 'UTF-8', 'ISO-8859-1', $child );
           echo '</' . $child->getName() . '>' . "\n";
        }
    }

   echo'</' . $parent->getName() . '>' . "\n";
}

0

我不明白为什么要这样做,因为SimpleXMLObject可以像数组一样处理...

但如果你真的需要这个功能,可以在这个帖子这篇文章中查看chassagnette的回答。


2
除非您想将其存储在会话中,否则在尝试时获取“不允许序列化'SimpleXMLElement'”的错误。因此,将其转换为数组是有用的。 - André van Schoubroeck
1
@GromBeestje:XML已经序列化了。在会话中存储字符串没有问题 :) - hakre
每次脚本加载时解析XML字符串似乎效率低下,因此我认为将其存储为已解析形式是有意义的。 - André van Schoubroeck

0
这里是我的迭代实现(即使我认为使用递归解析数据不会导致堆栈溢出)的递归转换为数组。这比通过json_decode函数传递更直接。
function xml2Array(SimpleXMLElement $el): stdClass {
    $ret = $el;
    $stack = [&$ret];
    while (count($stack) > 0) {
        $cur = &$stack[count($stack) - 1];
        array_splice($stack, -1);
        $cur = (object) (array) $cur;
        foreach ($cur as $key => $child) {
            $childRef = &$cur->{$key};
            if ($child instanceof SimpleXMLElement)
                $stack[count($stack) - 1] = &$childRef;
            elseif(is_array($child))
                foreach ($childRef as $ckey => $cell) {
                    if ($cell instanceof SimpleXMLElement)
                        $stack[count($stack) - 1] = &$childRef[$ckey];
                }
        }
    }
    return $ret;
}

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