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.

hache.
la source
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

Hanmant
la source
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>
*/
?>
Lalit
la source
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();
Francis Lewis
la source
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 ();
onokazu
la source
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();
}
user492589
la source
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');
Syl
la source
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);
Frans van Asselt
la source
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();
    ?>
CodePT
la source
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 :)

Neil anglais
la source
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.

lcornea
la source
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
drzaus
la source
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;
        }
    }
Mike
la source
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>
jtrumbull
la source
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();
caiofior
la source
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' => '[email protected]'
                ),

                '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());
    }
}      
Ardi
la source
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);
Gaius Baltar
la source
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.

Anthony
la source
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");
               }
          }
     }
}
Frankey
la source
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.

JosephVasantPrakash
la source
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;
}
Andrey
la source
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);
user2381982
la source
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

Daniele Orlando
la source
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);
?>
w35l3y
la source
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();
}
Kamil Dąbrowski
la source
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.

refeyd
la source
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);
            }
        }
    }
}   
Jouni Mäkeläinen
la source
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();
    }
}
as
la source
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.

Bharat Chodvadiya
la source
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);
    }
  }
}
Francisco Luz
la source