Comment convertir un tableau en SimpleXML


Réponses:


209

une courte:

<?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();

résulte en

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

les clés et les valeurs sont échangées - vous pouvez résoudre ce problème avec array_flip()avant le array_walk. array_walk_recursivenécessite PHP 5. vous pouvez utiliser à la array_walkplace, mais vous n'entrerez pas 'stack' => 'overflow'dans le xml alors.


53
Cela ne fonctionnera pas si $ test_array a 'more_another_array' comme 'another_array', car la clé 'another_array' n'est pas convertie. Vous aurez donc plusieurs '<overflow> pile </overflow>'.
comprendre

11
Le array_flipne fonctionnera pas car il ne peut pas retourner les tableaux (comme l' another_arrayintérieur du tableau principal).
Lode

14
Où est l'élément xml "another_array"? Tout est
aplati

2
A très bien fonctionné lorsque j'ai ajouté array_flip avant array_walk_recursive. Merci.
Mike Purcell

12
Downvoting car array_flipne fonctionne que si le tableau ne contient pas de valeurs identiques.
Martijn

385

Voici le code php 5.2 qui convertira un tableau de n'importe quelle profondeur en document 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
                        )   
                )

        )
)

le XML généré serait:

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

Extrait 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');

?>

Documentation SimpleXMLElement::asXMLutilisée dans cet extrait


40
Cela, l'OMI, est une bien meilleure solution que la réponse acceptée. Cependant, cela a la limitation qu'avec les tableaux à clé numérique, il génère du XML mal formé. <0> <1> <2> ne sont pas des noms de noeud valides.
KOGI

2
Cependant, si votre tableau à clé numérique ne contient qu'un autre tableau qui n'est pas à clé numérique, il ne le fera pas.
Bryan Petty

15
@KOGI J'ai modifié la réponse de Hanmant. Maintenant, il prend en charge les tableaux à plusieurs niveaux. pastebin.com/pYuXQWee
Mifas

1
Cet exemple échappe explicitement les caractères spéciaux dans les données de texte d'élément à l'aide de htmlspecialchars, mais SimpleXMLElement :: addChild traduit automatiquement les caractères spéciaux xml en leurs entités char afin que htmlspecialchars puisse être omis. Fait intéressant, cela ne semble pas entraîner de données à double fuite.
mbaynton

3
@Alex, votre édition # 5 fait échouer l'exemple. Il insère <item $ x> avant chaque enregistrement <student>, ce qui rend la sortie XML non conforme à l'intention de l'auteur. Peut-être fournir un exemple du problème que vous essayez de résoudre et nous pouvons trouver une autre solution pour les deux cas. Cela m'a pris un certain temps avant de réaliser que le code des auteurs avait été modifié.
Nicholas Blasgen

124

Les réponses fournies ici convertissent uniquement les tableaux en XML avec des nœuds, vous ne pouvez pas définir d'attributs. J'ai écrit une fonction php qui vous permet de convertir un tableau en php et également de définir des attributs pour des nœuds particuliers dans le xml. L'inconvénient ici est que vous devez construire un tableau d'une manière particulière avec peu de conventions (uniquement si vous souhaitez utiliser des attributs)

L'exemple suivant vous permettra également de définir des attributs en XML.

La source peut être trouvée ici: 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
Je suis surpris que personne n'ait réagi à ce sujet. Cette classe est vraiment utile car elle fait le contraire de ce que générera simpleXMLElement. Il vous donne donc la possibilité d'utiliser SimpleXMLElement dans les deux sens.
FMaz008

4
Je le marquerais comme réponse au lieu de courant. Réponse actuelle ne pas créer de tableaux récursifs
Oleksandr IY

2
Belle classe. J'ai modifié la ligne 128 if(!is_array($arr)) {pour if(!is_array($arr) && $arr !== '') {qu'elle n'ajoute pas un nouveau nœud de texte pour les chaînes vides et conserve donc le format de balise vide abrégé, c'est 'tag'=>''-à- dire <tag/>au lieu de<tag></tag>
user1433150

C'est la meilleure réponse jusqu'à présent. Cela a également la structure correcte de plusieurs éléments avec la même clé: le premier est la clé du nom du nœud, puis il contient le tableau avec des clés numériques. (l'opposé de la réponse Hanmant)
Vasil Popov

1
Trouvé un github de l'auteur @Legionar github.com/digitickets/lalit/blob/master/src/Array2XML.php
Daryl Teo

57

J'ai trouvé toutes les réponses pour utiliser trop de code. Voici un moyen simple de le faire:

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

Ensuite, il suffit d'envoyer le tableau dans la fonction, qui utilise la récursivité, de sorte qu'il gérera un tableau multidimensionnel:

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

Maintenant, $ xml contient un bel objet XML basé sur votre tableau exactement comme vous l'avez écrit.

print $xml->asXML();

9
J'adore le plus cette solution. Bien, ce serait bien d'ajouter un test sur les touches numériques, comme: if ( is_numeric( $key ) ) $key = "numeric_$key"; .
wout

@wout Bonne prise. Ajoutée. J'ai fait une vérification de cast int au lieu de is_numeric car is_numeric peut donner des résultats, bien que techniquement attendus, qui vous décourageraient vraiment.
Francis Lewis

J'utilise cette fonction, mais j'ai changé $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8" ?><rootTag/>');pour un encodage UTF-8 valide.
Daantje

Je aime cette solution le plus aussi bien, simple fait il :-) Une remarque: Vous voudrez peut - être changer $object->addChild($key, $value);pour $object->addChild($key, htmlspecialchars($value));l'empêcher de ne pas quand $ la valeur contient des caractères tels que « et » que XML-encodage besoin.
leo

38
<? php
fonction 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);
    }
    return $ xml;
}

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

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

1
cela échoue si votre tableau contient un tableau interne avec des index numériques. <0> ... </0> n'est pas un XML valide.
Adriano Varoli Piazza,

@AdrianoVaroliPiazza vient d'ajouter quelque chose comme $k = (is_numeric($k)) ? 'item' : $k;à l'intérieur duforeach()
AlienWebguy

Si l'une des clés du tableau est nommée "corps", cela ne fonctionne pas - plus précisément, la clé est ignorée et parcourue. Essayer de comprendre pourquoi.
Bambax

@Bambax La seule raison pour laquelle je peux penser est si le XML est analysé en HTML à un moment ultérieur.
Brilliand

16

Depuis 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();
}

Cela ressemble à une copie directe de la réponse sélectionnée, simplement insérée dans une fonction.
phaberest

J'ajouterais htmlspecialchars () à la partie addChild, comme ceci: $ xml-> addChild ($ key, htmlspecialchars ($ value));
Tyreal

15

Une autre amélioration:

/**
* 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();
}

Usage:

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

Je vous remercie! Votre fonction renvoie le contenu exact de tout tableau à n dimensions.
besciualex

12

Voici mon entrée, simple et propre ..

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

Donc de toute façon ... J'ai pris le code d'Onokazu (merci!) Et ajouté la possibilité d'avoir des balises répétées en XML, il prend également en charge les attributs, j'espère que quelqu'un le trouvera 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();
    ?>

Il pourrait être utile de commenter vos modifications pour rendre le code plus clair; encore, belle addition
StormeHawke

Cela a fonctionné pour moi avec WP All Export. J'ai dû changer légèrement la partie is_numeric: if (is_numeric($k)) { $i = $k + 1; $child = $xml->addChild("_$i"); array_to_xml($v, $child); }
performer

4

J'utilise quelques fonctions que j'ai écrites il y a quelque temps pour générer le xml pour passer de PHP à jQuery, etc. ) ...

S'il est utile à n'importe qui, veuillez l'utiliser :)

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

Amour à tous :)


4

Je voulais un code qui prendra tous les éléments d'un tableau et les traitera comme des attributs, et tous les tableaux comme des sous-éléments.

Donc, pour quelque chose comme

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

J'obtiendrais quelque chose comme ça

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

Pour y parvenir, le code est ci-dessous, mais soyez très prudent, il est récursif et peut en fait provoquer un 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();
} 

Vous voudrez peut-être ajouter des vérifications de la longueur du tableau afin que certains éléments soient définis à l'intérieur de la partie de données et non comme attribut.


4

Basé sur tout le reste ici, gère les indices + attributs numériques via le préfixe avec @, et pourrait injecter du xml dans les nœuds existants:

Code

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

Usage

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

Résultat

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

Une version mise à jour qui se répète comme des éléments enfants plutôt que des balises numériques: github.com/zaus/forms-3rdparty-xpost/blob/…
drzaus

3

Voici une fonction qui a fait l'affaire pour moi:

Appelez-le simplement avec quelque chose comme

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

Vous pouvez utiliser le XMLParser sur lequel je travaille.

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

Se traduirait par:

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

3

J'ai trouvé cette solution similaire au problème d'origine

<?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 plupart des réponses ci-dessus sont correctes. Cependant, j'ai trouvé cette réponse qui résout le problème de compatibilité array_walk_recursive et également le problème des clés numériques. Il a également réussi tous les tests que j'ai effectués:

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

J'ai également ajouté une classe de test pour cela qui peut vous être 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

autre solution:

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

Cela a un effet inattendu de création de XML de style RPC avec des éléments comme methodCall, methodName, scalaires et vecteurs, etc. Il ne s'agit pas vraiment de convertir un tableau en XML au sens simple.
Volomike

3

SI le tableau est associatif et correctement codé, il serait probablement plus facile de le transformer en xml en premier. Quelque chose comme:

  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'autre voie serait de créer d'abord votre xml de base, comme

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

puis pour chaque partie de votre tableau, utilisez quelque chose de similaire à ma boucle de création de texte et utilisez à la place les fonctions simplexml "addChild" pour chaque nœud du tableau.

Je vais essayer cela plus tard et mettre à jour ce message avec les deux versions.


Ce bit où j'ai mentionné "<array> </array>" m'a fait réaliser que la version chaîne avait besoin de quelque chose de similaire. Fondamentalement, le tableau doit avoir un nœud à l'extérieur. Laissez-moi dormir sur le tout, je vais avoir quelque chose qui rattrape cette erreur initiale tout de suite.
Anthony

2

Juste une modification sur une fonction ci-dessus, quand une touche est numérique, ajoutez un préfixe "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

Vous pouvez utiliser la fonction suivante dans votre code directement,

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

}

Appelez la fonction avec le premier argument comme tableau et le deuxième argument doit être 1, ce sera augmenté pour une indentation parfaite, et le troisième doit être vrai.

par exemple, si la variable de tableau à convertir est $ array1, alors l'appel serait, la fonction d'appel devrait être encapsulée avec une <pre>balise.

  artoxml ($ array1,1, true);   

Veuillez consulter la source de la page après avoir exécuté le fichier, car les symboles <et> ne seront pas affichés dans une page 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;
}

C'est une excellente option pour créer du XML DOMDocument. Merci @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;
}

Cette fonction retourne par exemple une liste de balises XML <obj>...</obj> <obj> ... </obj> pour les index numériques.

Contribution:

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

Production:

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

Cela devrait satisfaire tous les besoins communs. Vous pouvez peut-être changer la 3e ligne en:

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

ou si vous travaillez avec des pluriels se terminant par s:

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

1

Avec FluidXML, vous pouvez générer, à partir d'un tableau PHP , un XML pour SimpleXML avec ... seulement deux lignes de code.

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

Un exemple de tableau pourrait être

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

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


0

Vous pouvez utiliser xmlrpc_encode pour créer un xml à partir d'un tableau si un xml détaillé n'est pas un problème. www.php.net/xmlrpc_encode

attention le xml créé diffère si vous utilisez des touches associatives et / ou numériques

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

Cette fonction n'est pas prise en charge et, en fait, n'est pas fournie dans mes versions de PHP 5.2.16 ou PHP 5.3.5. (renvoie "PHP Fatal error: Call to undefined function xmlrpc_encode ()")
danorton

vous devez décommenter la ligne suivante dans php.ini: extension = php_xmlrpc.dll
w35l3y

@ w35l3y J'ai vérifié mon ini. Il ne contient même pas cette extension et j'utilise 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

Ma réponse, bricolant les réponses des autres. Cela devrait corriger l'échec de la compensation des touches numériques:

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()fonction suppose que le tableau se compose d'abord de touches numériques. Si votre tableau avait un élément initial, vous supprimeriez les instructions foreach()et $elemde la array_to_xml()fonction et passeriez simplement à la $xmlplace.


0

J'aurais commenté la deuxième réponse la plus votée, car elle ne préserve pas la structure et génère un mauvais XML s'il y a des tableaux internes indexés numériquement.

J'ai développé ma propre version sur cette base, car j'avais besoin d'un simple convertisseur entre json et xml quelle que soit la structure des données. Ma version préserve les informations des clés numériques et la structure du tableau d'origine. Il crée des éléments pour les valeurs indexées numériquement en encapsulant les valeurs dans les éléments nommés par valeur avec l'attribut clé qui contient la clé numérique.

Par exemple

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

convertit en

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

Ma version de array_to_xml -function (j'espère que cela aide quelqu'un :)

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

La structure XML entière est définie dans $ data Array:

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

Si vous travaillez dans magento et que vous avez ce type de tableau associatif

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

il est préférable de convertir le tableau associatif au format xml. Utilisez ce code dans le fichier contrôleur.

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

J'espère que cela aide à tous.


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);
    }
  }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.