Come convertire l'array in SimpleXML


Risposte:


209

uno breve:

<?php

$test_array = array (
  'bla' => 'blub',
  'foo' => 'bar',
  'another_array' => array (
    'stack' => 'overflow',
  ),
);
$xml = new SimpleXMLElement('<root/>');
array_walk_recursive($test_array, array ($xml, 'addChild'));
print $xml->asXML();

risultati in

<?xml version="1.0"?>
<root>
  <blub>bla</blub>
  <bar>foo</bar>
  <overflow>stack</overflow>
</root>

le chiavi e i valori vengono scambiati: potresti risolverlo con array_flip()prima di array_walk. array_walk_recursiverichiede PHP 5. è possibile utilizzare array_walkinvece, ma non si otterrà 'stack' => 'overflow'in xml allora.


53
Questo non funzionerà se $ test_array ha 'more_another_array' come 'another_array', perché la chiave 'another_array' non viene convertita. Quindi avrai più '<overflow> stack </overflow>'.
Comprendere il

11
Il array_flipnon funzionerà come può non array di vibrazione (come l' another_arrayinterno della matrice principale).
Lode,

14
Dov'è l'elemento xml "another_array"? Tutto è appiattito :(
FMaz008

2
Ha funzionato alla grande quando ho aggiunto array_flip prima di array_walk_recursive. Grazie.
Mike Purcell,

12
Downvoting perché array_flipfunziona solo se l'array non contiene valori identici.
Martijn,

385

Ecco il codice php 5.2 che converte array di qualsiasi profondità in documento XML:

Array
(
    ['total_stud']=> 500
    [0] => Array
        (
            [student] => Array
                (
                    [id] => 1
                    [name] => abc
                    [address] => Array
                        (
                            [city]=>Pune
                            [zip]=>411006
                        )                       
                )
        )
    [1] => Array
        (
            [student] => Array
                (
                    [id] => 2
                    [name] => xyz
                    [address] => Array
                        (
                            [city]=>Mumbai
                            [zip]=>400906
                        )   
                )

        )
)

l'XML generato sarebbe come:

<?xml version="1.0"?>
<student_info>
    <total_stud>500</total_stud>
    <student>
        <id>1</id>
        <name>abc</name>
        <address>
            <city>Pune</city>
            <zip>411006</zip>
        </address>
    </student>
    <student>
        <id>1</id>
        <name>abc</name>
        <address>
            <city>Mumbai</city>
            <zip>400906</zip>
        </address>
    </student>
</student_info>

Snippet PHP

<?php
// function defination to convert array to xml
function array_to_xml( $data, &$xml_data ) {
    foreach( $data as $key => $value ) {
        if( is_array($value) ) {
            if( is_numeric($key) ){
                $key = 'item'.$key; //dealing with <0/>..<n/> issues
            }
            $subnode = $xml_data->addChild($key);
            array_to_xml($value, $subnode);
        } else {
            $xml_data->addChild("$key",htmlspecialchars("$value"));
        }
     }
}

// initializing or creating array
$data = array('total_stud' => 500);

// creating object of SimpleXMLElement
$xml_data = new SimpleXMLElement('<?xml version="1.0"?><data></data>');

// function call to convert array to xml
array_to_xml($data,$xml_data);

//saving generated xml file; 
$result = $xml_data->asXML('/file/path/name.xml');

?>

Documentazione SimpleXMLElement::asXMLsull'uso in questo frammento


40
Questa, IMO, è una soluzione molto migliore della risposta accettata. Tuttavia, ciò ha la limitazione che con array a chiave numerica, genera XML non valido. <0> <1> <2> non sono nomi di nodi validi.
KOGI,

2
Tuttavia, se l'array a chiave numerica contiene solo un altro array che non è a chiave numerica, non lo farà.
Bryan Petty,

15
@KOGI Ho modificato la risposta Hanmant. Ora supporta matrici multilivello. pastebin.com/pYuXQWee
Mifas,

1
Questo esempio sfugge esplicitamente ai caratteri speciali nei dati di testo dell'elemento usando htmlspecialchars, ma SimpleXMLElement :: addChild traduce automaticamente i caratteri speciali xml nelle loro entità char in modo che htmlspecialchars possa essere escluso. È interessante notare che questo non sembra tradursi in dati doppiamente sfuggiti.
mbaynton,

3
@Alex, la tua Edit # 5 fa fallire l'esempio. Inserisce <item $ x> prima di ogni record <student> rendendo l'output XML non quello previsto dall'autore. Forse fornisci un esempio del problema che stai cercando di risolvere e possiamo trovare un'altra soluzione per entrambi i casi. Mi ci è voluto un po 'prima che mi rendessi conto che il codice degli autori era stato modificato.
Nicholas Blasgen,

124

Le risposte fornite qui convertono solo l'array in XML con nodi, non è possibile impostare gli attributi. Ho scritto una funzione php che ti consente di convertire un array in php e anche di impostare gli attributi per nodi particolari nell'xml. Il rovescio della medaglia qui è che devi costruire un array in un modo particolare con poche convenzioni (solo se vuoi usare gli attributi)

L'esempio seguente ti permetterà di impostare attributi anche in XML.

La fonte può essere trovata qui: https://github.com/digitickets/lalit/blob/master/src/Array2XML.php

<?php    
$books = array(
    '@attributes' => array(
        'type' => 'fiction'
    ),
    'book' => array(
        array(
            '@attributes' => array(
                'author' => 'George Orwell'
            ),
            'title' => '1984'
        ),
        array(
            '@attributes' => array(
                'author' => 'Isaac Asimov'
            ),
            'title' => 'Foundation',
            'price' => '$15.61'
        ),
        array(
            '@attributes' => array(
                'author' => 'Robert A Heinlein'
            ),
            'title' => 'Stranger in a Strange Land',
            'price' => array(
                '@attributes' => array(
                    'discount' => '10%'
                ),
                '@value' => '$18.00'
            )
        )
    )
);
/* creates 
<books type="fiction">
  <book author="George Orwell">
    <title>1984</title>
  </book>
  <book author="Isaac Asimov">
    <title>Foundation</title>
    <price>$15.61</price>
  </book>
  <book author="Robert A Heinlein">
    <title>Stranger in a Strange Land</title>
    <price discount="10%">$18.00</price>
  </book>
</books>
*/
?>

9
Sono convinto che nessuno abbia reagito a questo. Questa classe è davvero utile poiché sta facendo il contrario di ciò che genererà simpleXMLElement. Quindi ti dà la possibilità di utilizzare SimpleXMLElement in entrambi i modi.
FMaz008,

4
Lo contrassegnerei come risposta anziché corrente. Risposta attuale non creazione di array ricorsivi
Oleksandr IY

2
Bella classe. Ho modificato la riga 128 if(!is_array($arr)) {in if(!is_array($arr) && $arr !== '') {modo che non aggiunga un nuovo nodo di testo per stringhe vuote e quindi mantiene il formato di tag vuoto abbreviato cioè 'tag'=>''è <tag/>invece di<tag></tag>
user1433150

Questa è la risposta migliore finora. Inoltre, ha la struttura corretta di più elementi con la stessa chiave: la prima è la chiave del nome nodo, quindi contiene l'array con chiavi numeriche. (l'opposto della risposta Hanmant)
Vasil Popov,

1
Trovato un github dall'autore @Legionar github.com/digitickets/lalit/blob/master/src/Array2XML.php
Daryl Teo

57

Ho trovato tutte le risposte per usare troppo codice. Ecco un modo semplice per farlo:

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 == (int) $key) {
                $key = "key_$key";
            }

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

Quindi si tratta semplicemente di inviare l'array nella funzione, che utilizza la ricorsione, quindi gestirà un array multidimensionale:

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

Ora $ xml contiene un bellissimo oggetto XML basato sul tuo array esattamente come lo hai scritto.

print $xml->asXML();

9
Adoro questa soluzione di più. Anche se, sarebbe bello aggiungere un test su tasti numerici, come: if ( is_numeric( $key ) ) $key = "numeric_$key"; .
wout

@wout Buona cattura. Aggiunto. Ho fatto un controllo del cast int invece di is_numeric perché is_numeric può dare alcuni risultati, sebbene tecnicamente previsti, che potrebbero davvero farti perdere.
Francis Lewis,

Uso questa funzione, ma ho cambiato $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8" ?><rootTag/>');per una codifica UTF-8 valida.
Daantje,

Mi piace questa soluzione la più così, semplice lo fa :-) Un'altra osservazione: Si potrebbe desiderare di cambiare $object->addChild($key, $value);per $object->addChild($key, htmlspecialchars($value));per evitare che in mancanza quando $ valore contiene caratteri come "&" che hanno bisogno di XML-codifica.
leo

38
<? Php
funzione array_to_xml (array $ arr, SimpleXMLElement $ xml)
{
    foreach ($ arr as $ k => $ v) {
        is_array ($ v)
            ? array_to_xml ($ v, $ xml-> addChild ($ k))
            : $ xml-> addChild ($ k, $ v);
    }
    restituisce $ xml;
}

$ test_array = array (
    'bla' => 'blub',
    'foo' => 'bar',
    'another_array' => array (
        'stack' => 'overflow',
    ),
);

echo array_to_xml ($ test_array, nuovo SimpleXMLElement ('<root />')) -> asXML ();

1
ciò non riesce se l'array contiene un array interno con indici numerici. <0> ... </0> non è un XML valido.
Adriano Varoli Piazza

@AdrianoVaroliPiazza basta aggiungere qualcosa come $k = (is_numeric($k)) ? 'item' : $k;all'interno diforeach()
AlienWebguy

Se una delle chiavi dell'array è denominata "body", non funziona - più precisamente, la chiave viene ignorata e attraversata. Sto cercando di capire perché.
Bambax,

@Bambax L'unica ragione che mi viene in mente è se l'XML verrà analizzato come HTML in un secondo momento.
Brilliand,

16

Da PHP 5.4

function array2xml($data, $root = null){
    $xml = new SimpleXMLElement($root ? '<' . $root . '/>' : '<root/>');
    array_walk_recursive($data, function($value, $key)use($xml){
        $xml->addChild($key, $value);
    });
    return $xml->asXML();
}

Sembra una copia semplice della risposta selezionata, appena inserita in una funzione.
phaberest,

Aggiungerei htmlspecialchars () alla parte addChild, in questo modo: $ xml-> addChild ($ key, htmlspecialchars ($ value));
Tyreal,

15

Un altro miglioramento:

/**
* Converts an array to XML
*
* @param array $array
* @param SimpleXMLElement $xml
* @param string $child_name
*
* @return SimpleXMLElement $xml
*/
public function arrayToXML($array, SimpleXMLElement $xml, $child_name)
{
    foreach ($array as $k => $v) {
        if(is_array($v)) {
            (is_int($k)) ? $this->arrayToXML($v, $xml->addChild($child_name), $v) : $this->arrayToXML($v, $xml->addChild(strtolower($k)), $child_name);
        } else {
            (is_int($k)) ? $xml->addChild($child_name, $v) : $xml->addChild(strtolower($k), $v);
        }
    }

    return $xml->asXML();
}

Uso:

$this->arrayToXML($array, new SimpleXMLElement('<root/>'), 'child_name_to_replace_numeric_integers');

Grazie! La tua funzione restituisce il contenuto esatto di qualsiasi array n-dimensionale.
besciualex,

12

Ecco la mia voce, semplice e pulita ..

function array2xml($array, $xml = false){
    if($xml === false){
        $xml = new SimpleXMLElement('<root/>');
    }
    foreach($array as $key => $value){
        if(is_array($value)){
            array2xml($value, $xml->addChild($key));
        }else{
            $xml->addChild($key, $value);
        }
    }
    return $xml->asXML();
}


header('Content-type: text/xml');
print array2xml($array);

8

Quindi comunque ... ho preso il codice di onokazu (grazie!) E ho aggiunto la possibilità di avere tag ripetuti in XML, supporta anche gli attributi, spero che qualcuno lo trovi utile!

 <?php

function array_to_xml(array $arr, SimpleXMLElement $xml) {
        foreach ($arr as $k => $v) {

            $attrArr = array();
            $kArray = explode(' ',$k);
            $tag = array_shift($kArray);

            if (count($kArray) > 0) {
                foreach($kArray as $attrValue) {
                    $attrArr[] = explode('=',$attrValue);                   
                }
            }

            if (is_array($v)) {
                if (is_numeric($k)) {
                    array_to_xml($v, $xml);
                } else {
                    $child = $xml->addChild($tag);
                    if (isset($attrArr)) {
                        foreach($attrArr as $attrArrV) {
                            $child->addAttribute($attrArrV[0],$attrArrV[1]);
                        }
                    }                   
                    array_to_xml($v, $child);
                }
            } else {
                $child = $xml->addChild($tag, $v);
                if (isset($attrArr)) {
                    foreach($attrArr as $attrArrV) {
                        $child->addAttribute($attrArrV[0],$attrArrV[1]);
                    }
                }
            }               
        }

        return $xml;
    }

        $test_array = array (
          'bla' => 'blub',
          'foo' => 'bar',
          'another_array' => array (
            array('stack' => 'overflow'),
            array('stack' => 'overflow'),
            array('stack' => 'overflow'),
          ),
          'foo attribute1=value1 attribute2=value2' => 'bar',
        );  

        $xml = array_to_xml($test_array, new SimpleXMLElement('<root/>'))->asXML();

        echo "$xml\n";
        $dom = new DOMDocument;
        $dom->preserveWhiteSpace = FALSE;
        $dom->loadXML($xml);
        $dom->formatOutput = TRUE;
        echo $dom->saveXml();
    ?>

Potrebbe essere utile commentare le modifiche per rendere più chiaro il codice; ancora, bella aggiunta
StormeHawke

Questo ha funzionato per me con WP All Export. Ho dovuto cambiare leggermente la parte is_numerica: if (is_numeric($k)) { $i = $k + 1; $child = $xml->addChild("_$i"); array_to_xml($v, $child); }
risultato

4

Uso un paio di funzioni che ho scritto qualche tempo fa per generare l'xml per passare avanti e indietro da PHP e jQuery ecc ... Né utilizzare alcun framework aggiuntivo genera semplicemente una stringa che può quindi essere utilizzata con SimpleXML (o altro framework ) ...

Se è utile a chiunque, ti preghiamo di usarlo :)

function generateXML($tag_in,$value_in="",$attribute_in=""){
    $return = "";
    $attributes_out = "";
    if (is_array($attribute_in)){
        if (count($attribute_in) != 0){
            foreach($attribute_in as $k=>$v):
                $attributes_out .= " ".$k."=\"".$v."\"";
            endforeach;
        }
    }
    return "<".$tag_in."".$attributes_out.((trim($value_in) == "") ? "/>" : ">".$value_in."</".$tag_in.">" );
}

function arrayToXML($array_in){
    $return = "";
    $attributes = array();
    foreach($array_in as $k=>$v):
        if ($k[0] == "@"){
            // attribute...
            $attributes[str_replace("@","",$k)] = $v;
        } else {
            if (is_array($v)){
                $return .= generateXML($k,arrayToXML($v),$attributes);
                $attributes = array();
            } else if (is_bool($v)) {
                $return .= generateXML($k,(($v==true)? "true" : "false"),$attributes);
                $attributes = array();
            } else {
                $return .= generateXML($k,$v,$attributes);
                $attributes = array();
            }
        }
    endforeach;
    return $return;
}   

Amore a tutti :)


4

Volevo un codice che prendesse tutti gli elementi all'interno di un array e li trattasse come attributi e tutti gli array come elementi secondari.

Quindi per qualcosa del genere

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

Vorrei ottenere qualcosa del genere

<?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>

Per raggiungere questo obiettivo il codice è sotto, ma fai molta attenzione, è ricorsivo e può effettivamente causare uno 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();
} 

È possibile che si desideri aggiungere controlli per la lunghezza dell'array in modo che alcuni elementi vengano impostati all'interno della parte dati e non come attributo.


4

Basato su tutto il resto qui, gestisce indici numerici + attributi tramite prefisso con @e potrebbe iniettare xml in nodi esistenti:

Codice

function simple_xmlify($arr, SimpleXMLElement $root = null, $el = 'x') {
    // based on, among others http://stackoverflow.com/a/1397164/1037948

    if(!isset($root) || null == $root) $root = new SimpleXMLElement('<' . $el . '/>');

    if(is_array($arr)) {
        foreach($arr as $k => $v) {
            // special: attributes
            if(is_string($k) && $k[0] == '@') $root->addAttribute(substr($k, 1),$v);
            // normal: append
            else simple_xmlify($v, $root->addChild(
                    // fix 'invalid xml name' by prefixing numeric keys
                    is_numeric($k) ? 'n' . $k : $k)
                );
        }
    } else {
        $root[0] = $arr;
    }

    return $root;
}//--   fn  simple_xmlify

uso

// lazy declaration via "queryparam"
$args = 'hello=4&var[]=first&var[]=second&foo=1234&var[5]=fifth&var[sub][]=sub1&var[sub][]=sub2&var[sub][]=sub3&var[@name]=the-name&var[@attr2]=something-else&var[sub][@x]=4.356&var[sub][@y]=-9.2252';
$q = array();
parse_str($val, $q);

$xml = simple_xmlify($q); // dump $xml, or...
$result = get_formatted_xml($xml); // see below

Risultato

<?xml version="1.0"?>
<x>
  <hello>4</hello>
  <var name="the-name" attr2="something-else">
    <n0>first</n0>
    <n1>second</n1>
    <n5>fifth</n5>
    <sub x="4.356" y="-9.2252">
      <n0>sub1</n0>
      <n1>sub2</n1>
      <n2>sub3</n2>
    </sub>
  </var>
  <foo>1234</foo>
</x>

Bonus: formattazione XML

function get_formatted_xml(SimpleXMLElement $xml, $domver = null, $preserveWhitespace = true, $formatOutput = true) {
    // http://stackoverflow.com/questions/1191167/format-output-of-simplexml-asxml

    // create new wrapper, so we can get formatting options
    $dom = new DOMDocument($domver);
    $dom->preserveWhiteSpace = $preserveWhitespace;
    $dom->formatOutput = $formatOutput;
    // now import the xml (converted to dom format)
    /*
    $ix = dom_import_simplexml($xml);
    $ix = $dom->importNode($ix, true);
    $dom->appendChild($ix);
    */
    $dom->loadXML($xml->asXML());

    // print
    return $dom->saveXML();
}//--   fn  get_formatted_xml

Una versione aggiornata che si ripete come elementi figlio anziché tag numerici: github.com/zaus/forms-3rdparty-xpost/blob/…
drzaus,

3

Ecco una funzione che ha fatto il trucco per me:

Chiamalo semplicemente con qualcosa del genere

echo arrayToXml("response",$arrayIWantToConvert);
function arrayToXml($thisNodeName,$input){
        if(is_numeric($thisNodeName))
            throw new Exception("cannot parse into xml. remainder :".print_r($input,true));
        if(!(is_array($input) || is_object($input))){
            return "<$thisNodeName>$input</$thisNodeName>";
        }
        else{
            $newNode="<$thisNodeName>";
            foreach($input as $key=>$value){
                if(is_numeric($key))
                    $key=substr($thisNodeName,0,strlen($thisNodeName)-1);
                $newNode.=arrayToXml3($key,$value);
            }
            $newNode.="</$thisNodeName>";
            return $newNode;
        }
    }

3

Potresti usare XMLParser su cui ho lavorato.

$xml = XMLParser::encode(array(
    'bla' => 'blub',
    'foo' => 'bar',
    'another_array' => array (
        'stack' => 'overflow',
    )
));
// @$xml instanceof SimpleXMLElement
echo $xml->asXML();

Si tradurrebbe in:

<?xml version="1.0"?>
<root>
    <bla>blub</bla>
    <foo>bar</foo>
    <another_array>
        <stack>overflow</stack>
    </another_array>
</root>

3

Ho trovato questa soluzione simile al problema originale

<?php

$test_array = array (
  'bla' => 'blub',
  'foo' => 'bar',
  'another_array' => array (
    'stack' => 'overflow',
  ),
);

class NoSimpleXMLElement extends SimpleXMLElement {
 public function addChild($name,$value) {
  parent::addChild($value,$name);
 }
}
$xml = new NoSimpleXMLElement('<root/>');
array_walk_recursive($test_array, array ($xml, 'addChild'));
print $xml->asXML();

3

La maggior parte delle risposte di cui sopra sono corrette. Tuttavia, ho trovato questa risposta che risolve il problema di compatibilità array_walk_recursive e anche il problema dei tasti numerici. Ha anche superato tutti i test che ho fatto:

function arrayToXML(Array $array, SimpleXMLElement &$xml) {

    foreach($array as $key => $value) {

        // None array
        if (!is_array($value)) {
            (is_numeric($key)) ? $xml->addChild("item$key", $value) : $xml->addChild($key, $value);
            continue;
        }   

        // Array
        $xmlChild = (is_numeric($key)) ? $xml->addChild("item$key") : $xml->addChild($key);
        arrayToXML($value, $xmlChild);
    }
}   

Ho anche aggiunto una classe di test per questo che potresti trovare utile:

class ArrayToXmlTest extends PHPUnit_Framework_TestCase {

    public function setUp(){ }
    public function tearDown(){ }

    public function testFuncExists() {
        $this->assertTrue(function_exists('arrayToXML'));
    }

    public function testFuncReturnsXml() {
        $array = array(
            'name' => 'ardi',
            'last_name' => 'eshghi',
            'age' => 31,
            'tel' => '0785323435'
        );

        $xmlEl =  new SimpleXMLElement('<root/>');
        arrayToXml($array, $xmlEl);

        $this->assertTrue($xmlEl instanceOf SimpleXMLElement);
    }

    public function testAssocArrayToXml() {

        $array = array(
            'name' => 'ardi',
            'last_name' => 'eshghi',
            'age' => 31,
            'tel' => '0785323435'
        );

        $expectedXmlEl = new SimpleXMLElement('<root/>'); 
        $expectedXmlEl->addChild('name', $array['name']);
        $expectedXmlEl->addChild('last_name', $array['last_name']);
        $expectedXmlEl->addChild('age', $array['age']);
        $expectedXmlEl->addChild('tel', $array['tel']);

        $actualXmlEl =  new SimpleXMLElement('<root/>');
        arrayToXml($array, $actualXmlEl);

        $this->assertEquals($expectedXmlEl->asXML(), $actualXmlEl->asXML());
    }

    public function testNoneAssocArrayToXml() {

        $array = array(
            'ardi',
            'eshghi',
            31,
            '0785323435'
        );

        // Expected xml value
        $expectedXmlEl = new SimpleXMLElement('<root/>'); 
        foreach($array as $key => $value)
            $expectedXmlEl->addChild("item$key", $value);

        // What the function produces       
        $actualXmlEl =  new SimpleXMLElement('<root/>');
        arrayToXml($array, $actualXmlEl);

        $this->assertEquals($expectedXmlEl->asXML(), $actualXmlEl->asXML());
    }

    public function testNestedMixArrayToXml() {

        $testArray = array(
            "goal",
            "nice",
            "funny" => array(
                'name' => 'ardi',
                'tel'   =>'07415517499',
                "vary",
                "fields" => array(
                    'small',
                    'email' => 'ardi.eshghi@gmail.com'
                ),

                'good old days'

            ),

            "notes" => "come on lads lets enjoy this",
            "cast" => array(
                'Tom Cruise',
                'Thomas Muller' => array('age' => 24)
            )
        );

        // Expected xml value
        $expectedXmlEl = new SimpleXMLElement('<root/>'); 
        $expectedXmlEl->addChild('item0', $testArray[0]);
        $expectedXmlEl->addChild('item1', $testArray[1]);
        $childEl = $expectedXmlEl->addChild('funny');
        $childEl->addChild("name", $testArray['funny']['name']);
        $childEl->addChild("tel", $testArray['funny']['tel']);
        $childEl->addChild("item0", "vary");
        $childChildEl = $childEl->addChild("fields");
        $childChildEl->addChild('item0', 'small');
        $childChildEl->addChild('email', $testArray['funny']['fields']['email']);
        $childEl->addChild("item1", 'good old days');
        $expectedXmlEl->addChild('notes', $testArray['notes']);
        $childEl2 = $expectedXmlEl->addChild('cast');
        $childEl2->addChild('item0', 'Tom Cruise');
        $childChildEl2 = $childEl2->addChild('Thomas Muller');
        $childChildEl2->addChild('age', $testArray['cast']['Thomas Muller']['age']);

        // What the function produces       
        $actualXmlEl = new SimpleXMLElement('<root/>');
        arrayToXml($testArray, $actualXmlEl);

        $this->assertEquals($expectedXmlEl->asXML(), $actualXmlEl->asXML());
    }
}      

3

altra soluzione:

$marray=array(....);
$options = array(
                "encoding" => "UTF-8",
                "output_type" => "xml", 
                "version" => "simple",
                "escaping" => array("non-ascii, on-print, markup")
                );
$xmlres = xmlrpc_encode_request('root', $marray, $options);
print($xmlres);

Ciò ha un effetto inaspettato nel creare XML in stile RPC con elementi come methodCall, methodName, scalari e vettori, ecc. Non sta realmente convertendo un array in XML in senso semplice.
Volomike,

3

SE l'array è associativo e digitato correttamente, probabilmente sarebbe più semplice trasformarlo prima in XML. Qualcosa di simile a:

  function array2xml ($array_item) {
    $xml = '';
    foreach($array_item as $element => $value)
    {
        if (is_array($value))
        {
            $xml .= "<$element>".array2xml($value)."</$element>";
        }
        elseif($value == '')
        {
            $xml .= "<$element />";
        }
        else
        {
            $xml .= "<$element>".htmlentities($value)."</$element>";
        }
    }
    return $xml;
}

$simple_xml = simplexml_load_string(array2xml($assoc_array));

L'altro percorso sarebbe quello di creare prima il tuo xml di base, come

$simple_xml = simplexml_load_string("<array></array>");

e quindi per ogni parte dell'array, usa qualcosa di simile al mio ciclo di creazione del testo e usa invece le funzioni simplexml "addChild" per ciascun nodo dell'array.

Lo proverò più tardi e aggiornerò questo post con entrambe le versioni.


Quel bit in cui ho citato "<array> </array>" mi ha fatto capire che la versione di stringa ha bisogno di qualcosa di simile. Fondamentalmente l'array deve avere un nodo all'esterno. Fammi dormire tutto, avrò qualcosa che colma subito l'errore iniziale.
Anthony,

2

Solo una modifica su una funzione sopra, quando una chiave è numerica, aggiungi un prefisso "key_"

// initializing or creating array
$student_info = array(your array data);

// creating object of SimpleXMLElement
$xml_student_info = new SimpleXMLElement("<?xml version=\"1.0\"?><student_info></student_info>");

// function call to convert array to xml
array_to_xml($student,$xml_student_info);

//saving generated xml file
$xml_student_info->asXML('file path and name');


function array_to_xml($student_info, &$xml_student_info) {
     foreach($student_info as $key => $value) {
          if(is_array($value)) {
            if(!is_numeric($key)){
                $subnode = $xml_student_info->addChild("$key");
                array_to_xml($value, $subnode);
            }
            else{
                $subnode = $xml_student_info->addChild("key_$key");
                array_to_xml($value, $subnode);
            }
          }
          else {
               if(!is_numeric($key)){
                    $xml_student_info->addChild("$key","$value");
               }else{
                    $xml_student_info->addChild("key_$key","$value");
               }
          }
     }
}

1

Puoi usare direttamente la seguente funzione nel tuo codice,

    function artoxml($arr, $i=1,$flag=false){
    $sp = "";
    for($j=0;$j<=$i;$j++){
        $sp.=" ";
     }
    foreach($arr as $key=>$val){
        echo "$sp&lt;".$key."&gt;";
        if($i==1) echo "\n";
        if(is_array($val)){
            if(!$flag){echo"\n";}
            artoxml($val,$i+5);
            echo "$sp&lt;/".$key."&gt;\n";
        }else{
              echo "$val"."&lt;/".$key."&gt;\n";
         }
    }

}

Chiamare la funzione con il primo argomento come array e il secondo argomento deve essere 1, questo verrà aumentato per un rientro perfetto e il terzo deve essere vero.

ad esempio, se la variabile dell'array da convertire è $ array1, la chiamata sarebbe, la funzione chiamante dovrebbe essere incapsulata con il <pre>tag.

  artoxml ($ array1,1, true);   

Vedere l'origine della pagina dopo aver eseguito il file, poiché i simboli <e> non verranno visualizzati in una pagina HTML.


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

Questa è un'opzione eccellente per la creazione di DOMDocument xml. Grazie @Andrey
altsyset

1
function array2xml(array $data, SimpleXMLElement $object = null, $oldNodeName = 'item')
{
    if (is_null($object)) $object = new SimpleXMLElement('<root/>');
    $isNumbered = true;
    $idx = 0;
    foreach ($data as $key => $x)
        if (is_string($key) || ($idx++ != $key + 0))
            $isNumbered = false;
    foreach ($data as $key => $value)
    {   
        $attribute = preg_match('/^[0-9]/', $key . '') ? $key : null;
        $key = (is_string($key) && !preg_match('/^[0-9]/', $key . '')) ? $key : preg_replace('/s$/', '', $oldNodeName);
        if (is_array($value))
        {
            $new_object = $object->addChild($key);
            if (!$isNumbered && !is_null($attribute)) $new_object->addAttribute('id', $attribute);
            array2xml($value, $new_object, $key);
        }
        else
        {
            if (is_bool($value)) $value = $value ? 'true' : 'false';
            $node = $object->addChild($key, htmlspecialchars($value));
            if (!$isNumbered && !is_null($attribute) && !isset($node->attributes()->id))
                $node->addAttribute('id', $attribute);
        }
    }
    return $object;
}

Questa funzione restituisce ad esempio un elenco di <obj>...</obj> <obj> ... </obj> tag XML per indici numerici.

Ingresso:

    array(
    'people' => array(
        'dog',
        'cat',
        'life' => array(
            'gum',
            'shoe',
        ),
        'fish',
    ),
    array('yeah'),
)

Produzione:

<root>
    <people>
        <people>dog</people>
        <people>cat</people>
        <life>
            <life>gum</life>
            <life>shoe</life>
        </life>
        <people>fish</people>
        <people>
            <people>yeah</people>
        </people>
    </people>
</root>

Questo dovrebbe soddisfare tutte le esigenze comuni. Forse puoi cambiare la 3a riga in:

$key = is_string($key) ? $key : $oldNodeName . '_' . $key;

o se stai lavorando con plurali che terminano con s:

$key = is_string($key) ? $key : preg_replace('/s$/', '', $oldNodeName);

1

Con FluidXML è possibile generare, a partire da un array PHP , un XML per SimpleXML con ... solo due righe di codice.

$fluidxml  = fluidxml($array);
$simplexml = simplexml_import_dom($fluidxml->dom());

Un esempio di array potrebbe essere

$array = [ 'doc' => [
              'fruit' => 'orange',
              'cake'  => [
                   '@id' => '123', 
                   '@'   => 'tiramisu' ],
              [ 'pasta' => 'matriciana' ],
              [ 'pasta' => 'boscaiola'  ]
] ];

https://github.com/servo-php/fluidxml


0

È possibile utilizzare xmlrpc_encode per creare un XML dall'array se un XML dettagliato non è un problema. www.php.net/xmlrpc_encode

fai attenzione che l'xml creato differisca nel caso in cui usi chiavi associative e / o numeriche

<?php
// /params/param/value/struct/member
// there is a tag "member" for each element
// "member" contains a tag "name". its value is the associative key
$xml1 = xmlrpc_encode(array('a'=>'b','c'=>'d'));
$simplexml1 = simplexml_load_string($xml1);
print_r($xml1);
print_r($simplexml1);

// /params/param/value/array/data
// there is a tag "data" for each element
// "data" doesn't contain the tag "name"
$xml2 = xmlrpc_encode(array('a','b'));
$simplexml2 = simplexml_load_string($xml2);
print_r($xml2);
print_r($simplexml2);
?>

Questa funzione non è supportata e, di fatto, non è disponibile nelle mie build di PHP 5.2.16 o PHP 5.3.5. (restituisce "Errore irreversibile PHP: chiamata alla funzione indefinita xmlrpc_encode ()")
danorton

devi decommentare la seguente riga in php.ini: extension = php_xmlrpc.dll
w35l3y

@ w35l3y Ho controllato il mio ini. Non contiene nemmeno quell'estensione e sto usando la v 5.3.6.
Mike S.

0
function array2xml($array, $xml = false){

    if($xml === false){

        $xml = new SimpleXMLElement('<?xml version=\'1.0\' encoding=\'utf-8\'?><'.key($array).'/>');
        $array = $array[key($array)];

    }
    foreach($array as $key => $value){
        if(is_array($value)){
            $this->array2xml($value, $xml->addChild($key));
        }else{
            $xml->addChild($key, $value);
        }
    }
    return $xml->asXML();
}

0

La mia risposta, mettendo insieme le risposte degli altri. Ciò dovrebbe correggere la mancata compensazione dei tasti numerici:

function array_to_xml($array, $root, $element) {
    $xml = new SimpleXMLElement("<{$root}/>");
    foreach ($array as $value) {
        $elem = $xml->addChild($element);
        xml_recurse_child($elem, $value);
    }
    return $xml;
}

function xml_recurse_child(&$node, $child) {
    foreach ($child as $key=>$value) {
        if(is_array($value)) {
            foreach ($value as $k => $v) {
                if(is_numeric($k)){
                    xml_recurse_child($node, array($key => $v));
                }
                else {
                    $subnode = $node->addChild($key);
                    xml_recurse_child($subnode, $value);
                }
            }
        }
        else {
            $node->addChild($key, $value);
        }
    }   
}

La array_to_xml()funzione presuppone che l'array sia composto innanzitutto da tasti numerici. Se il tuo array avesse un elemento iniziale, elimineresti le istruzioni foreach()e $elemdalla array_to_xml()funzione e passeresti semplicemente $xml.


0

Avrei commentato la seconda risposta più votata, perché non preserva la struttura e genera xml errati se ci sono array interni indicizzati numericamente.

Ho sviluppato la mia versione basata su di essa, perché avevo bisogno di un semplice convertitore tra json e xml indipendentemente dalla struttura dei dati. La mia versione conserva le informazioni sulla chiave numerica e la struttura dell'array originale. Crea elementi per i valori indicizzati numericamente avvolgendo i valori in elementi con valori nominali con attributo chiave che contiene chiave numerica.

Per esempio

array('test' => array(0 => 'some value', 1 => 'other'))

converte in

<test><value key="0">some value</value><value key="1">other</value></test>

La mia versione di array_to_xml -function (spero che aiuti qualcuno :)

function array_to_xml($arr, &$xml) {
    foreach($arr as $key => $value) {
        if(is_array($value)) {
            if(!is_numeric($key)){
                $subnode = $xml->addChild("$key");
            } else {
                $subnode = $xml->addChild("value");
                $subnode->addAttribute('key', $key);                    
            }
            array_to_xml($value, $subnode);
        }
        else {
            if (is_numeric($key)) {
                $xml->addChild("value", $value)->addAttribute('key', $key);
            } else {
                $xml->addChild("$key",$value);
            }
        }
    }
}   

0

L'intera struttura XML è definita nell'array $ data:

function array2Xml($data, $xml = null)
{
    if (is_null($xml)) {
        $xml = simplexml_load_string('<' . key($data) . '/>');
        $data = current($data);
        $return = true;
    }
    if (is_array($data)) {
        foreach ($data as $name => $value) {
            array2Xml($value, is_numeric($name) ? $xml : $xml->addChild($name));
        }
    } else {
        $xml->{0} = $data;
    }
    if (!empty($return)) {
        return $xml->asXML();
    }
}

0

Se lavori in magento e hai questo tipo di array associativo

$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'
    ),
);

quindi è meglio convertire l'array associativo in formato xml. Utilizzare questo codice nel file controller.

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

Spero che aiuti a tutti.


0

// Structered array for XML convertion.
$data_array = array(
  array(
    '#xml_tag' => 'a',
    '#xml_value' => '',
    '#tag_attributes' => array(
      array(
        'name' => 'a_attr_name',
        'value' => 'a_attr_value',
      ),
    ),
    '#subnode' => array(
      array(
        '#xml_tag' => 'aa',
        '#xml_value' => 'aa_value',
        '#tag_attributes' => array(
          array(
            'name' => 'aa_attr_name',
            'value' => 'aa_attr_value',
          ),
        ),
        '#subnode' => FALSE,
      ),
    ),
  ),
  array(
    '#xml_tag' => 'b',
    '#xml_value' => 'b_value',
    '#tag_attributes' => FALSE,
    '#subnode' => FALSE,
  ),
  array(
    '#xml_tag' => 'c',
    '#xml_value' => 'c_value',
    '#tag_attributes' => array(
      array(
        'name' => 'c_attr_name',
        'value' => 'c_attr_value',
      ),
      array(
        'name' => 'c_attr_name_1',
        'value' => 'c_attr_value_1',
      ),
    ),
    '#subnode' => array(
      array(
        '#xml_tag' => 'ca',  
        '#xml_value' => 'ca_value',
        '#tag_attributes' => FALSE,
        '#subnode' => array(
          array(
            '#xml_tag' => 'caa',
            '#xml_value' => 'caa_value',
            '#tag_attributes' => array(
              array(
                'name' => 'caa_attr_name',
                'value' => 'caa_attr_value',
              ),
            ),
            '#subnode' => FALSE,
          ),
        ),
      ),
    ),
  ),
);


// creating object of SimpleXMLElement
$xml_object = new SimpleXMLElement('<?xml version=\"1.0\"?><student_info></student_info>');


// function call to convert array to xml
array_to_xml($data_array, $xml_object);

// saving generated xml file
$xml_object->asXML('/tmp/test.xml');

/**
 * Converts an structured PHP array to XML.
 *
 * @param Array $data_array
 *   The array data for converting into XML.
 * @param Object $xml_object
 *   The SimpleXMLElement Object
 *
 * @see https://gist.github.com/drupalista-br/9230016
 * 
 */
function array_to_xml($data_array, &$xml_object) {
  foreach($data_array as $node) {
    $subnode = $xml_object->addChild($node['#xml_tag'], $node['#xml_value']);

    if ($node['#tag_attributes']) {
      foreach ($node['#tag_attributes'] as $tag_attributes) {
        $subnode->addAttribute($tag_attributes['name'], $tag_attributes['value']); 
      }
    }

    if ($node['#subnode']) {
      array_to_xml($node['#subnode'], $subnode);
    }
  }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.