php: export array to xml trouble

2019-03-06 09:56发布

问题:

I have an array which I need to convert to XML with SimpleXML. The method below is almost doing the work but there's one trouble with it. It can't generate structure like this:

    $xmlFields = array(  
        'rootElt' => array(
            'field1' => '',
            'field2' => '',                
            'field3' => array(                  
                'field4'  => array(
                    'income' => array(
                        'owner' => '',                            
                        'description' => '', 
                    ),
                    'income' => array(
                        'owner' => '',                            
                        'description' => '', 
                    ),
                ),
            )
        )
    );

It writes only the last 'income' of section 'field4' but I need the output like:

<field4>
    <income>
        <owner>....</owner>            
        <description>....</description>
    </income>
    <income>
        <owner>....</owner>            
        <description>....</description>
    </income>
</field4>

Could someone help me fix this function:

/**     
 * @param array $dataArr
 * @param SimpleXMLElement $xmlObj 
 */
private function array2xml( $dataArr, $xmlObj ) {
    foreach ( $dataArr as $key => $value ) {          
        if ( is_array($value) ) {                        
            if ( !is_numeric($key) ) {                    
                $subnode = $xmlObj->addChild( $key );                    
                self::array2xml( $value, $subnode );                    
            } else {                                        
                self::array2xml( $value, $xmlObj );      
            }
        } else {
            $xmlObj->addChild( $key, $value );                       
        }
    }
}

回答1:

The code looks fine in terms of SimpleXML, however you have a misunderstanding of how arrays work in PHP:

'field4'  => array(
    'income' => array(
        'owner' => '',                            
        'description' => '', 
    ),
    'income' => array(
        'owner' => '',                            
        'description' => '', 
    ),

That is not adding two values to the field4 array, but one. See http://php.net/array, for example Example #2. The second definition of the income key replaces the first one.

What you might want to do in this case is to use a different structure with your array:

'field4'  => array(
    array('income' => array(
        'owner' => '',                            
        'description' => '', 
    )),
    array('income' => array(
        'owner' => '',                            
        'description' => '', 
    )),

If you wrap each element inside an array element it's own, your code would even not have any special cases because each element is the same. However this would mean that you would - if you create the array by hand - write more code to define it.

Another alternative that comes to mind would be this:

'field4'  => array(
    'income' => array(
        array(
            'owner' => '',                            
            'description' => '', 
        ),
        array(
            'owner' => '',                            
            'description' => '', 
        ),            
    ),

This still wouldn't you allow to have multiple groups with the same element name, but writing it would be probably easier.

For the later array structure (I think that's what you wanted to use), I've created a simplexml array importer / converter (Gist). The usage is pretty straight forward in it's basic form, but you can do even more differentiated stuff with it:

/* Example 1: Create a new SimpleXMLElement based on an array */

$import = new SimpleXMLArrayImport();

$xml = $import->importArray(['root' => '']);

/* <?xml version="1.0"?>
 * <root/>                                                    */

/* Example 2: Add an empty child element to the root          */

$new = $import->addArray($xml, ['numbers' => '']);

/* <?xml version="1.0"?>
 * <root>
 *   <numbers/>
 * </root>                                                    */

/* Example 3: Add a list of same-named elements to the root   */

$last = $import->addArray($new, ['number' => [0, 1, 42]]);

/* <?xml version="1.0"?>
 * <root>
 *     <numbers>
 *         <number>0</number>
 *         <number>1</number>
 *         <number>42</number>
 *     </numbers>
 * </root>                                                    */

/* Example 4: Set attribute of last added element             */

$last['note'] = 'The Answer to the Ultimate Question of Life, the Universe, and Everything';

/* <?xml version="1.0"?>
 * <root>
 *   <numbers>
 *     <number>0</number>
 *     <number>1</number>
 *     <number note="The Answer to the ...">42</number>
 *   </numbers>
 * </root>                                                    */

/* Example 5: Create a full document                          */

$xmlFields = array(
    'rootElt' => array(
        'field1' => '',
        'field2' => '',
        'field3' => array(
            'field4' => array(
                'income' => array(
                    array(
                        'owner'       => '',
                        'description' => '',
                    ),
                    array(
                        'owner'       => '',
                        'description' => '',
                    ),
                ),
            ),
        )
    )
);

$import = new SimpleXMLArrayImport($xmlFields);

$xml = $import->getDocument(); # The SimpleXML Root Element

/* <?xml version="1.0"?>
 * <rootElt>
 *   <field1/>
 *   <field2/>
 *   <field3>
 *     <field4>
 *       <income>
 *         <owner/>
 *         <description/>
 *       </income>
 *       <income>
 *         <owner/>
 *         <description/>
 *       </income>
 *     </field4>
 *   </field3>
 * </rootElt>                                                 */