Comment convertir xml en tableau en php?

167

Je veux convertir ci-dessous XML en tableau PHP. Des suggestions sur la façon dont je peux faire cela?

<aaaa Version="1.0">
   <bbb>
     <cccc>
       <dddd Id="id:pass" />
       <eeee name="hearaman" age="24" />
     </cccc>
   </bbb>
</aaaa>
Hearaman
la source
3
aussi, en quoi cette question est-elle différente de votre autre question? stackoverflow.com/questions/6578084/…
Gordon
3
Peu de choses sont aussi odieuses qu'un OP acceptant la mauvaise réponse à sa propre question.
John

Réponses:

128

Une autre option est l'extension SimpleXML (je pense qu'elle est fournie en standard avec la plupart des installations php.)

http://php.net/manual/en/book.simplexml.php

La syntaxe ressemble à ceci pour votre exemple

$xml = new SimpleXMLElement($xmlString);
echo $xml->bbb->cccc->dddd['Id'];
echo $xml->bbb->cccc->eeee['name'];
// or...........
foreach ($xml->bbb->cccc as $element) {
  foreach($element as $key => $val) {
   echo "{$key}: {$val}";
  }
}
Sam Dufel
la source
82
Pour être juste, cela ne répond pas exactement à la question de savoir comment obtenir un tableau.
sieppl
SimpleXML est nul lors de l'analyse de ce xml: amazon.in/rss/bestsellers/shoes?tag=dealslama-21 Même print_r ne dit pas que l'objet contient réellement.
ravisoni
utilisez var_dump, vous verrez la structure xml comme des clés à l'intérieur de l'objet.
Magus
3
J'ai [CDATA[TEXT]]quelques éléments à l'intérieur et ils ne sont pas analysés avec cela. Il l'analyse comme un fichier SimpleXMLElement Object. Une solution de contournement pour cela?
masterFly
Cela ne répond pas à la question
Bilaal Rashid
435

facile!

$xml = simplexml_load_string($xmlstring, "SimpleXMLElement", LIBXML_NOCDATA);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
user1398287
la source
20
Vous pourriez rencontrer des problèmes dans les sections CDATA (renvoyant toujours null). En guise de solution, essayez $ xml = simplexml_load_string ($ xmlstring, null, LIBXML_NOCDATA); $ json = json_encode ($ xml); $ array = json_decode ($ json, TRUE); (voir stackoverflow.com/a/2970701/413531 ) // e putain .. y a-t-il un moyen d'ajouter de nouvelles lignes dans un commentaire?
Hirnhamster
4
Nous faisons exactement la même chose mais avec simplexml_load_file et cela fonctionne bien. Merci
Thermech
2
À quoi sert le deuxième paramètre (TRUE)?
Mansour Fahad
3
@MansourFahad Dans json_decode, vous pouvez utiliser le deuxième paramètre facultatif comme TRUE(normalement par défaut FALSE) pour convertir l'entrée JSON en un tableau associatif.
Jake Bathman
16
@Ismael Miguel trop de code? Ce n'est pas parce que vous mettez toutes ces fonctions sur une seule ligne que vous utilisez moins de code. Cela peut paraître plus compact, mais cela se fait au détriment de la lisibilité.
Jage
44

Conversion d'une chaîne XML ( $buffer) en un tableau simplifié ignorant les attributs et regroupant les éléments enfants avec les mêmes noms:

function XML2Array(SimpleXMLElement $parent)
{
    $array = array();

    foreach ($parent as $name => $element) {
        ($node = & $array[$name])
            && (1 === count($node) ? $node = array($node) : 1)
            && $node = & $node[];

        $node = $element->count() ? XML2Array($element) : trim($element);
    }

    return $array;
}

$xml   = simplexml_load_string($buffer);
$array = XML2Array($xml);
$array = array($xml->getName() => $array);

Résultat:

Array
(
    [aaaa] => Array
        (
            [bbb] => Array
                (
                    [cccc] => Array
                        (
                            [dddd] => 
                            [eeee] => 
                        )

                )

        )

)

Si vous souhaitez également avoir les attributs, ils sont disponibles via l'encodage / décodage JSON de SimpleXMLElement. C'est souvent la solution quick'n'dirty la plus simple:

$xml   = simplexml_load_string($buffer);
$array = json_decode(json_encode((array) $xml), true);
$array = array($xml->getName() => $array);

Résultat:

Array
(
    [aaaa] => Array
        (
            [@attributes] => Array
                (
                    [Version] => 1.0
                )

            [bbb] => Array
                (
                    [cccc] => Array
                        (
                            [dddd] => Array
                                (
                                    [@attributes] => Array
                                        (
                                            [Id] => id:pass
                                        )

                                )

                            [eeee] => Array
                                (
                                    [@attributes] => Array
                                        (
                                            [name] => hearaman
                                            [age] => 24
                                        )

                                )

                        )

                )

        )

)

Notez que toutes ces méthodes ne fonctionnent que dans l'espace de noms du document XML.

hakre
la source
En PHP 7 je devais ajouter ceci: && (is_countable($node) && 1 === count($node) ? $node = array($node) : 1), mais je suis une erreur dans la ligne suivante: [] operator not supported for strings.
andreshg112
@ andreshg112: Je suis incapable de reproduire (fonctionne de manière stable PHP 5.3.0 - 7.4.0), le comportement n'a pas changé depuis des siècles, veuillez comparer avec des centaines de versions de PHP différentes: 3v4l.org/l4nQN
hakre
c'est peut-être à cause de mon fichier KML (c'est un XML). Je ne peux pas le partager. Je l'ai déjà importé mais j'ai dû le faire d'une autre manière.
andreshg112
vous êtes probablement préoccupé par les espaces de noms XML. L'exemple ne concerne que les parties sans espace de noms (ou celui par défaut, je mélange parfois cela).
hakre
25
$array = json_decode(json_encode((array)simplexml_load_string($xml)),true);
Fawad Ghafoor
la source
1
si vous lancez vers un tableau, vous n'avez pas besoin de json_encodeet json_decode.
Ismael Miguel
11
@Ismael en théorie, la conversion en tableau devrait suffire. En pratique, nous devons également convertir tous les nœuds feuilles, qui sont également des objets. Un casting naïf laisse les feuilles comme des objets SimpleXML. json_encode lance récursivement en sauvant beaucoup de travail.
Peter Mellett
2
Si vous n'avez pas de valeurs de texte dans votre $arrayvariable, c'est peut-être à cause de CDATA. Pour le résoudre, chargez votre XML avec: new SimpleXMLElement($xml, LIBXML_NOCDATA).
Jonathan Petitcolas
1
ps. $ xml = str_replace (tableau ('<! [CDATA [', ']]>'), '', $ xml);
user956584
1
Ça ne marche pas comme ça. Ce code ne convertirait même pas un simple XML comme celui-ci <?xml version="1.0" encoding="UTF-8"?><note a="b"><body c="d">Hello!</body></note>. Exécutez le code et vous verrez que l' attribut <body> c est perdu! Veuillez vérifier le code complet ici si vous ne voulez pas de mauvaises surprises github.com/gaarf/XML-string-to-PHP-array/blob/master/… ou voir ma réponse ci-dessous stackoverflow.com/a/30234924/828366
Francesco Casula
8

Surpris personne n'a mentionné xml_parse_into_struct:

$simple = "<para><note>simple note</note></para>";
$p = xml_parser_create();
xml_parse_into_struct($p, $simple, $vals, $index);
xml_parser_free($p);
echo "Index array\n";
print_r($index);
echo "\nVals array\n";
print_r($vals);
éozzy
la source
Parfois, je me demande ce que pensait le développeur qui a créé l'implémentation PHP XML lorsque xml_parse_into_struct a été conçu ...
Anibal Sanchez
7

Voir https://github.com/gaarf/XML-string-to-PHP-array/blob/master/xmlstr_to_array.php

<?php
/**
  * convert xml string to php array - useful to get a serializable value
  *
  * @param string $xmlstr
  * @return array
  *
  * @author Adrien aka Gaarf & contributors
  * @see http://gaarf.info/2009/08/13/xml-string-to-php-array/
*/
function xmlstr_to_array($xmlstr) {
  $doc = new DOMDocument();
  $doc->loadXML($xmlstr);
  $root = $doc->documentElement;
  $output = domnode_to_array($root);
  $output['@root'] = $root->tagName;
  return $output;
}
function domnode_to_array($node) {
  $output = array();
  switch ($node->nodeType) {
    case XML_CDATA_SECTION_NODE:
    case XML_TEXT_NODE:
      $output = trim($node->textContent);
    break;
    case XML_ELEMENT_NODE:
      for ($i=0, $m=$node->childNodes->length; $i<$m; $i++) {
        $child = $node->childNodes->item($i);
        $v = domnode_to_array($child);
        if(isset($child->tagName)) {
          $t = $child->tagName;
          if(!isset($output[$t])) {
            $output[$t] = array();
          }
          $output[$t][] = $v;
        }
        elseif($v || $v === '0') {
          $output = (string) $v;
        }
      }
      if($node->attributes->length && !is_array($output)) { //Has attributes but isn't an array
        $output = array('@content'=>$output); //Change output into an array.
      }
      if(is_array($output)) {
        if($node->attributes->length) {
          $a = array();
          foreach($node->attributes as $attrName => $attrNode) {
            $a[$attrName] = (string) $attrNode->value;
          }
          $output['@attributes'] = $a;
        }
        foreach ($output as $t => $v) {
          if(is_array($v) && count($v)==1 && $t!='@attributes') {
            $output[$t] = $v[0];
          }
        }
      }
    break;
  }
  return $output;
}
Francesco Casula
la source
7

La méthode utilisée dans les attributs de suppression de réponse acceptés lors de la rencontre d'éléments enfants avec uniquement un nœud de texte. Par exemple:

$xml = '<container><element attribute="123">abcd</element></container>';
print_r(json_decode(json_encode(simplexml_load_string($xml, "SimpleXMLElement", LIBXML_NOCDATA)),1));

Array
(
    [element] => abcd
)

Ma solution (et j'aimerais pouvoir donner du crédit ici car je suis sûr que j'ai adapté cela à partir de quelque chose):

function XMLtoArray($xml) {
    $previous_value = libxml_use_internal_errors(true);
    $dom = new DOMDocument('1.0', 'UTF-8');
    $dom->preserveWhiteSpace = false; 
    $dom->loadXml($xml);
    libxml_use_internal_errors($previous_value);
    if (libxml_get_errors()) {
        return [];
    }
    return DOMtoArray($dom);
}

function DOMtoArray($root) {
    $result = array();

    if ($root->hasAttributes()) {
        $attrs = $root->attributes;
        foreach ($attrs as $attr) {
            $result['@attributes'][$attr->name] = $attr->value;
        }
    }

    if ($root->hasChildNodes()) {
        $children = $root->childNodes;
        if ($children->length == 1) {
            $child = $children->item(0);
            if (in_array($child->nodeType,[XML_TEXT_NODE,XML_CDATA_SECTION_NODE])) {
                $result['_value'] = $child->nodeValue;
                return count($result) == 1
                    ? $result['_value']
                    : $result;
            }

        }
        $groups = array();
        foreach ($children as $child) {
            if (!isset($result[$child->nodeName])) {
                $result[$child->nodeName] = DOMtoArray($child);
            } else {
                if (!isset($groups[$child->nodeName])) {
                    $result[$child->nodeName] = array($result[$child->nodeName]);
                    $groups[$child->nodeName] = 1;
                }
                $result[$child->nodeName][] = DOMtoArray($child);
            }
        }
    }
    return $result;
}

$xml = '
    <aaaa Version="1.0">
       <bbb>
         <cccc>
           <dddd id="123" />
           <eeee name="john" age="24" />
           <ffff type="employee">Supervisor</ffff>
         </cccc>
       </bbb>
    </aaaa>
';
print_r(XMLtoArray($xml));

Array
(
    [aaaa] => Array
        (
            [@attributes] => Array
                (
                    [Version] => 1.0
                )

            [bbb] => Array
                (
                    [cccc] => Array
                        (
                            [dddd] => Array
                                (
                                    [@attributes] => Array
                                        (
                                            [id] => 123
                                        )

                                )

                            [eeee] => Array
                                (
                                    [@attributes] => Array
                                        (
                                            [name] => john
                                            [age] => 24
                                        )

                                )

                            [ffff] => Array
                                (
                                    [@attributes] => Array
                                        (
                                            [type] => employee
                                        )

                                    [_value] => Supervisor
                                )

                        )

                )

        )

)
Billynoah
la source
2

XML vers tableau

Plus de détails Visitez https://github.com/sapankumarmohanty/lamp/blob/master/Crate-XML-2-Array

// Convertit XML en tableau et SOAP XML en tableau

function xml2array($contents, $get_attributes = 1, $priority = 'tag')
    {
        if (!$contents) return array();
        if (!function_exists('xml_parser_create')) {
            // print "'xml_parser_create()' function not found!";
            return array();
        }
        // Get the XML parser of PHP - PHP must have this module for the parser to work
        $parser = xml_parser_create('');
        xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8"); // http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss
        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
        xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
        xml_parse_into_struct($parser, trim($contents) , $xml_values);
        xml_parser_free($parser);
        if (!$xml_values) return; //Hmm...
        // Initializations
        $xml_array = array();
        $parents = array();
        $opened_tags = array();
        $arr = array();
        $current = & $xml_array; //Refference
        // Go through the tags.
        $repeated_tag_index = array(); //Multiple tags with same name will be turned into an array
        foreach($xml_values as $data) {
            unset($attributes, $value); //Remove existing values, or there will be trouble
            // This command will extract these variables into the foreach scope
            // tag(string), type(string), level(int), attributes(array).
            extract($data); //We could use the array by itself, but this cooler.
            $result = array();
            $attributes_data = array();
            if (isset($value)) {
                if ($priority == 'tag') $result = $value;
                else $result['value'] = $value; //Put the value in a assoc array if we are in the 'Attribute' mode
            }
            // Set the attributes too.
            if (isset($attributes) and $get_attributes) {
                foreach($attributes as $attr => $val) {                                   
                                    if ( $attr == 'ResStatus' ) {
                                        $current[$attr][] = $val;
                                    }
                    if ($priority == 'tag') $attributes_data[$attr] = $val;
                    else $result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
                }
            }
            // See tag status and do the needed.
                        //echo"<br/> Type:".$type;
            if ($type == "open") { //The starting of the tag '<tag>'
                $parent[$level - 1] = & $current;
                if (!is_array($current) or (!in_array($tag, array_keys($current)))) { //Insert New tag
                    $current[$tag] = $result;
                    if ($attributes_data) $current[$tag . '_attr'] = $attributes_data;
                                        //print_r($current[$tag . '_attr']);
                    $repeated_tag_index[$tag . '_' . $level] = 1;
                    $current = & $current[$tag];
                }
                else { //There was another element with the same tag name
                    if (isset($current[$tag][0])) { //If there is a 0th element it is already an array
                        $current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
                        $repeated_tag_index[$tag . '_' . $level]++;
                    }
                    else { //This section will make the value an array if multiple tags with the same name appear together
                        $current[$tag] = array(
                            $current[$tag],
                            $result
                        ); //This will combine the existing item and the new item together to make an array
                        $repeated_tag_index[$tag . '_' . $level] = 2;
                        if (isset($current[$tag . '_attr'])) { //The attribute of the last(0th) tag must be moved as well
                            $current[$tag]['0_attr'] = $current[$tag . '_attr'];
                            unset($current[$tag . '_attr']);
                        }
                    }
                    $last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
                    $current = & $current[$tag][$last_item_index];
                }
            }
            elseif ($type == "complete") { //Tags that ends in 1 line '<tag />'
                // See if the key is already taken.
                if (!isset($current[$tag])) { //New Key
                    $current[$tag] = $result;
                    $repeated_tag_index[$tag . '_' . $level] = 1;
                    if ($priority == 'tag' and $attributes_data) $current[$tag . '_attr'] = $attributes_data;
                }
                else { //If taken, put all things inside a list(array)
                    if (isset($current[$tag][0]) and is_array($current[$tag])) { //If it is already an array...
                        // ...push the new element into that array.
                        $current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
                        if ($priority == 'tag' and $get_attributes and $attributes_data) {
                            $current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
                        }
                        $repeated_tag_index[$tag . '_' . $level]++;
                    }
                    else { //If it is not an array...
                        $current[$tag] = array(
                            $current[$tag],
                            $result
                        ); //...Make it an array using using the existing value and the new value
                        $repeated_tag_index[$tag . '_' . $level] = 1;
                        if ($priority == 'tag' and $get_attributes) {
                            if (isset($current[$tag . '_attr'])) { //The attribute of the last(0th) tag must be moved as well
                                $current[$tag]['0_attr'] = $current[$tag . '_attr'];
                                unset($current[$tag . '_attr']);
                            }
                            if ($attributes_data) {
                                $current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
                            }
                        }
                        $repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
                    }
                }
            }
            elseif ($type == 'close') { //End of tag '</tag>'
                $current = & $parent[$level - 1];
            }
        }
        return ($xml_array);
    }
    
    // Let's call the this above function xml2array
    
    xml2array($xmlContent, $get_attributes = 3, $priority = 'tag'); // it will work 100% if not ping me @skype: sapan.mohannty
    
//  Enjoy coding
htngapi
la source
0

J'ai aimé cette question et certaines réponses m'ont été utiles, mais je dois convertir le XML en un tableau de domination, donc je publierai ma solution peut-être que quelqu'un en aura besoin plus tard:

<?php
$xml = json_decode(json_encode((array)simplexml_load_string($xml)),1);
$finalItem = getChild($xml);
var_dump($finalItem);

function getChild($xml, $finalItem = []){
    foreach($xml as $key=>$value){
        if(!is_array($value)){
            $finalItem[$key] = $value;
        }else{
            $finalItem = getChild($value, $finalItem);
        }
    }
    return $finalItem;
}
?>  
Mohammad Alabed
la source