【问题标题】:Recursive cast from SimpleXMLObject to Array从 SimpleXML 对象到数组的递归转换
【发布时间】:2010-10-24 12:11:10
【问题描述】:

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

这可能吗?

【问题讨论】:

    标签: php casting simplexml


    【解决方案1】:
    json_decode(json_encode((array) simplexml_load_string($obj)), 1);
    

    【讨论】:

    • 聪明!我从来没有想过这样做。
    • 如果可能的话,我会给你 100 票。它真是太棒了:)
    • @AdamLibuša 是的,但是你如何将属性保存在 php 数组中?
    • 说真的,这个答案怎么能被接受?它不适用于最简单的测试用例:<?php $xml = '<?xml version="1.0" encoding="utf-8"?><data><empty/></data>'; $array = json_decode(json_encode((array) simplexml_load_string($xml)), 1); var_dump($array); ?> empty 将被转换为空数组而不是 null
    • 还有一个很大的缺点,它将所有内容都转换为字符串。但是当你有布尔值或整数时,它们都会被强制转换为不是最优的字符串。
    【解决方案2】:

    没有测试这个,但这似乎可以完成:

    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

    【讨论】:

    • 不确定这对其他人如何“不起作用”,但它完成了遍历所有子元素和属性的工作。
    【解决方案3】:

    这是可能的。这是一个递归函数,它打印出父元素的标签以及没有更多子元素的标签+内容。你可以改变它来构建一个数组:

    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";
    }
    

    【讨论】:

      【解决方案4】:

      我不明白这一点,因为 SimpleXMLObject 可以像数组一样受到威胁......

      但如果你真的需要,只需在论坛中查看 chassagnette 在this threadthis post 中的回答。

      【讨论】:

      • 除非您想将其存储在会话中,否则当我尝试这样做时,会出现“不允许序列化 'SimpleXMLElement'”。因此转换为数组很有用
      • @GromBeestje:XML 已经序列化。在会话中存储字符串没有问题:)
      • 每次加载脚本时解析 XML 字符串似乎效率低下,因此我认为存储解析后的表单是有意义的。
      【解决方案5】:

      取决于 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;
      }
      

      【讨论】:

        【解决方案6】:

        这是我的 iterative(即使我认为您不会通过使用递归解析数据而导致堆栈爆炸)实现递归转换为数组。这是一种比通过 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;
        }
        

        【讨论】:

          【解决方案7】:

          对于那些对 CDATA 案有疑虑的人,

          将@ajayi-oluwaseun-emmanuel 的回答与this answer 结合起来对我有用:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-09-04
            • 1970-01-01
            • 2017-03-26
            • 1970-01-01
            • 2011-06-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多