如何将数组转换为PHP中的SimpleXML对象?


当前回答

我认为上面所有的解决方案都很好,但我看到目前为止,它并没有真正创建一个准确的格式良好的XML,因为数组键与$my_array[main_node][multiple_values][] = ARRAY ('id' => '1')然后转换为

    <main_node>
       <multiple_values>
         <0>
           <id>1 test</id>
         </0>
       </multiple_values>
       <multiple_values>
         <1>
          <id>2 test</id>
         </1>
       </multiple_values>
    </main_node>

这是XML解析器方面的一个问题……

I should be like this:

    <main_node>
     <multiple_values>
      <id>1 test</id>
     </multiple_values>
     <multiple_values>
      <id>2 test</id>
     </multiple_values>
    </main_node>

如果你用load_simple_xml来解析…你会得到完全相同的数组/对象结构。

我的函数还自动创建正确的根节点。

    // Code to convert php array to xml document 20211112
    function array2xml(array $data, $xml_class_obj = '', $group_by_parent_allowed = '', $options = array())
        {   
            
            if(!$xml_class_obj) :
                $is_root = 1;
                $xml_class_obj = new XMLWriter();
                $xml_class_obj->openMemory();
                $xml_class_obj->setIndent(TRUE);
                $xml_class_obj->setIndentString('   ');
                if($options['encoding'] != '')  $xml_class_obj->startDocument('1.0', $options['encoding']);
                else                                                        $xml_class_obj->startDocument('1.0');
            endif;
            
            foreach ($data as $key => $value) {

                if (is_array($value)) { // IS ARRAY

                    // check if allow below keys are int, if yes group them to same parent tree
                    $group_by_parent = $key;
                    foreach(array_keys($value) as $c_keys) :
                        if(!is_int($c_keys)) $group_by_parent = '';
                    endforeach;

                    if(empty($group_by_parent)) $xml_class_obj->startElement($key); 
                    if($group_by_parent_allowed != '') $xml_class_obj->startElement($group_by_parent_allowed);
                    
                    $this->array2xml($value, $xml_class_obj, $group_by_parent, $options);
                    
                    if(empty($group_by_parent)) $xml_class_obj->endElement();  

                } else { // IS VALUE
                    
                    if(is_string($value)) :
                        $xml_class_obj->startElement($key);
                        $xml_class_obj->writeCData($value);         
                        $xml_class_obj->endElement();           
                    else :
                        $xml_class_obj->writeElement($key, $value); 
                    endif;

                }

            } // foreach
            
            if($group_by_parent_allowed != '')  $xml_class_obj->endElement(); 
            
            if($is_root == 1) :
            
                $xml_class_obj->endDocument();
                return $xml_class_obj->outputMemory();
            else :              
                return $xml_class_obj;                  
            endif;
              
        }  
    
    // usage
    $ary_new_xml = array();
    $ary_new_xml['order']['customer']['customerid'] = '123456'; 
    $ary_new_xml['order']['customer']['customertype'] = 15; 
            
    $ary_new_xml['order']['orderprio'] = 2; 
            
    $ary_new_xml['order']['orderpos'][] = array('sku' => 9999910001111, 'quantity' => 3);           
    $ary_new_xml['order']['orderpos'][] = array('sku' => 9999910002222, 'quantity' => 1); 
            
echo array2xml($ary_new_xml,'','',array('enconding' => 'UTF-8'));

结果:

<?xml version="1.0" encoding="UTF-8"?>
<order>
   <customer>
      <customerid>82936639</customerid>
      <customertype>15</customertype>
   </customer>
   <orderprio>2</orderprio>
   <orderpos>
      <sku>9999910001111</sku>
      <quantity>3</quantity>
   </orderpos>
   <orderpos>
      <sku>9999910002222</sku>
      <quantity>1</quantity>
   </orderpos>
</order>


 

我希望这能帮助到一些人;)

其他回答

我想要一个代码,将一个数组内的所有元素,并把它们作为属性,所有数组作为子元素。

对于像这样的东西

array (
'row1' => array ('head_element' =>array("prop1"=>"some value","prop2"=>array("empty"))),
"row2"=> array ("stack"=>"overflow","overflow"=>"overflow")
);

我会得到这样的结果

<?xml version="1.0" encoding="utf-8"?>
<someRoot>
  <row1>
    <head_element prop1="some value">
      <prop2 0="empty"/>
    </head_element>
  </row1>
  <row2 stack="overflow" overflow="stack"/>
 </someRoot>

要实现这一点,代码如下,但要非常小心,它是递归的,实际上可能会导致stackoverflow:)

function addElements(&$xml,$array)
{
$params=array();
foreach($array as $k=>$v)
{
    if(is_array($v))
        addElements($xml->addChild($k), $v);
    else $xml->addAttribute($k,$v);
}

}
function xml_encode($array)
{
if(!is_array($array))
    trigger_error("Type missmatch xml_encode",E_USER_ERROR);
$xml=new SimpleXMLElement('<?xml version=\'1.0\' encoding=\'utf-8\'?><'.key($array).'/>');
addElements($xml,$array[key($array)]);
return $xml->asXML();
} 

您可能希望添加数组长度检查,以便在数据部分中设置某些元素,而不是作为属性。

function toXML($data, $obj = false, $dom) {
    $is_first_level = false;
    if($obj === false) {
        $dom = new DomDocument('1.0');
        $obj = $dom;
        $is_first_level = true;
    }

    if(is_array($data)) {
        foreach($data as $key => $item) {
            $this->toXML($item, $obj->appendChild($dom->createElement($key)), $dom);
        }
    }else {
        $obj->appendChild($dom->createTextNode($data));
    }

    if($is_first_level) {
        $obj->formatOutput = true;
        return $obj->saveXML();
    }
    return $obj;
}

你可以使用胡子模板引擎,并制作一个模板,如:

{{#RECEIVER}}
<RECEIVER>
    <COMPANY>{{{COMPANY}}}</COMPANY>
    <CONTACT>{{{CONTACT}}}</CONTACT>
    <ADDRESS>{{{ADDRESS}}}</ADDRESS>
    <ZIP>{{ZIP}}</ZIP>
    <CITY>{{{CITY}}}</CITY>
</RECEIVER>
{{/RECEIVER}}
{{#DOC}}
<DOC>
    <TEXT>{{{TEXT}}}</TEXT>
    <NUMBER>{{{NUMBER}}}</NUMBER>
</DOC>
{{/DOC}}

在PHP中这样使用它:

require_once( __DIR__ .'/../controls/Mustache/Autoloader.php' );
Mustache_Autoloader::register();
$oMustache = new Mustache_Engine();
$sTemplate = implode( '', file( __DIR__ ."/xml.tpl" ));
$return = $oMustache->render($sTemplate, $res);
echo($return);

如果你使用magento,你有这种类型的关联数组

$test_array = array (
    '0' => array (
            'category_id' => '582',
            'name' => 'Surat',
            'parent_id' => '565',
            'child_id' => '567',
            'active' => '1',
            'level' => '6',
            'position' => '17'
    ),

    '1' => array (
            'category_id' => '567', 
            'name' => 'test',
            'parent_id' => '0',
            'child_id' => '576',
            'active' => '0',
            'level' => '0',
            'position' => '18'
    ),
);

那么最好将关联数组转换为XML格式。在控制器文件中使用此代码。

$this->loadLayout(false);
//header ("content-type: text/xml");
$this->getResponse()->setHeader('Content-Type','text/xml');
$this->renderLayout();

$clArr2xml = new arr2xml($test_array, 'utf-8', 'listdata');
$output = $clArr2xml->get_xml();
print $output; 

class arr2xml
{
var $array = array();
var $xml = '';
var $root_name = '';
var $charset = '';

public function __construct($array, $charset = 'utf-8', $root_name = 'root')
{
    header ("content-type: text/xml");
    $this->array = $array;
    $this->root_name = $root_name;
    $this->charset = $charset;

    if (is_array($array) && count($array) > 0) {
        $this->struct_xml($array);

    } else {
        $this->xml .= "no data";
    }
}

public function struct_xml($array)
{
    foreach ($array as $k => $v) {
        if (is_array($v)) {
            $tag = ereg_replace('^[0-9]{1,}', 'item', $k); // replace numeric key in array to 'data'
            $this->xml .= "<$tag>";
            $this->struct_xml($v);
            $this->xml .= "</$tag>";
        } else {
            $tag = ereg_replace('^[0-9]{1,}', 'item', $k); // replace numeric key in array to 'data'
            $this->xml .= "<$tag><![CDATA[$v]]></$tag>";
        }
    }
}

public function get_xml()
{

    $header = "<?xml version=\"1.0\" encoding=\"" . $this->charset . "\"?><" . $this->root_name . ">";
    $footer = "</" . $this->root_name . ">";

    return $header . $this->xml . $footer;
}
}

我希望这对大家都有帮助。

我发现所有的答案都是使用过多的代码。这里有一个简单的方法:

function to_xml(SimpleXMLElement $object, array $data)
{   
    foreach ($data as $key => $value) {
        if (is_array($value)) {
            $new_object = $object->addChild($key);
            to_xml($new_object, $value);
        } else {
            // if the key is an integer, it needs text with it to actually work.
            if ($key != 0 && $key == (int) $key) {
                $key = "key_$key";
            }

            $object->addChild($key, $value);
        }   
    }   
}   

然后,将数组发送到使用递归的函数中就很简单了,因此它将处理多维数组:

$xml = new SimpleXMLElement('<rootTag/>');
to_xml($xml, $my_array);

现在$xml包含了一个漂亮的xml对象,它完全基于您编写数组的方式。

print $xml->asXML();