PHP convertit du XML en JSON

158

J'essaie de convertir xml en json en php. Si je fais une simple conversion en utilisant du xml simple et json_encode aucun des attributs dans le spectacle xml.

$xml = simplexml_load_file("states.xml");
echo json_encode($xml);

J'essaye donc de l'analyser manuellement comme ceci.

foreach($xml->children() as $state)
{
    $states[]= array('state' => $state->name); 
}       
echo json_encode($states);

et la sortie de l'état est {"state":{"0":"Alabama"}}plutôt que{"state":"Alabama"}

Qu'est-ce que je fais mal?

XML:

<?xml version="1.0" ?>
<states>
    <state id="AL">     
    <name>Alabama</name>
    </state>
    <state id="AK">
        <name>Alaska</name>
    </state>
</states>

Production:

[{"state":{"0":"Alabama"}},{"state":{"0":"Alaska"}

var dump:

object(SimpleXMLElement)#1 (1) {
["state"]=>
array(2) {
[0]=>
object(SimpleXMLElement)#3 (2) {
  ["@attributes"]=>
  array(1) {
    ["id"]=>
    string(2) "AL"
  }
  ["name"]=>
  string(7) "Alabama"
}
[1]=>
object(SimpleXMLElement)#2 (2) {
  ["@attributes"]=>
  array(1) {
    ["id"]=>
    string(2) "AK"
  }
  ["name"]=>
  string(6) "Alaska"
}
}
}
Bryan Hadlock
la source
Veuillez inclure un extrait du code XML et la structure de tableau finale que vous avez après son analyse. (A var_dumpfonctionne bien.)
nikc.org
ajout d'entrée, de sortie et var_dump
Bryan Hadlock
Certaines applications ont besoin d'une "mappe XML-JSON perfec", c'est-à- dire jsonML , voir la solution ici .
Peter Krauss

Réponses:

473

Json & Array de XML en 3 lignes:

$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
Antonio Max
la source
59
Cette solution n'est pas irréprochable. Il rejette complètement les attributs XML. Ainsi <person my-attribute='name'>John</person>est interprété comme <person>John</person>.
Jake Wilson
13
$ xml = simplexml_load_string ($ xml_string, 'SimpleXMLElement', LIBXML_NOCDATA); pour aplatir les éléments cdata.
txyoji le
28
@JakeWilson est peut-être les 2 ans qui se sont écoulés, et diverses corrections de version, mais sur PHP 5.6.30, cette méthode produit TOUTES les données. Les attributs sont stockés dans le tableau sous la @attributesclé, donc cela fonctionne parfaitement et parfaitement. 3 courtes lignes de code résolvent magnifiquement mon problème.
AlexanderMP
1
Cela ne fonctionne pas si vous avez plusieurs espaces de noms, vous ne pouvez en choisir qu'un, qui passera dans la $ json_string: '(
jirislav
1
Gardez à l'esprit qu'avec cette solution, lorsqu'il peut y avoir plusieurs nœuds avec le même nom, un nœud entraînera une clé pointant simplement vers un élément, mais plusieurs nœuds entraîneront une clé pointant vers un tableau d'éléments: <list><item><a>123</a><a>456</a></item><item><a>123</a></item></list>-> {"item":[{"a":["123","456"]},{"a":"123"}]}. Une solution sur php.net par ratfactor résout ce problème en stockant toujours les éléments dans un tableau.
Klesun
37

Désolé d'avoir répondu à un ancien message, mais cet article décrit une approche relativement courte, concise et facile à maintenir. Je l'ai testé moi-même et fonctionne plutôt bien.

http://lostechies.com/seanbiefeld/2011/10/21/simple-xml-to-json-with-php/

<?php   
class XmlToJson {
    public function Parse ($url) {
        $fileContents= file_get_contents($url);
        $fileContents = str_replace(array("\n", "\r", "\t"), '', $fileContents);
        $fileContents = trim(str_replace('"', "'", $fileContents));
        $simpleXml = simplexml_load_string($fileContents);
        $json = json_encode($simpleXml);

        return $json;
    }
}
?>
Coreus
la source
4
Cela ne fonctionnera pas si vous avez plusieurs instances de la même balise dans votre XML, json_encode finira par ne sérialiser que la dernière instance de la balise.
ethree
35

Je l'ai compris. json_encode gère les objets différemment des chaînes. J'ai jeté l'objet en une chaîne et cela fonctionne maintenant.

foreach($xml->children() as $state)
{
    $states[]= array('state' => (string)$state->name); 
}       
echo json_encode($states);
Bryan Hadlock
la source
19

Je suppose que je suis un peu en retard à la fête mais j'ai écrit une petite fonction pour accomplir cette tâche. Il prend également en charge les attributs, le contenu du texte et même si plusieurs nœuds avec le même nom de nœud sont des frères.

Avertissement: je ne suis pas natif de PHP, alors veuillez supporter de simples erreurs.

function xml2js($xmlnode) {
    $root = (func_num_args() > 1 ? false : true);
    $jsnode = array();

    if (!$root) {
        if (count($xmlnode->attributes()) > 0){
            $jsnode["$"] = array();
            foreach($xmlnode->attributes() as $key => $value)
                $jsnode["$"][$key] = (string)$value;
        }

        $textcontent = trim((string)$xmlnode);
        if (count($textcontent) > 0)
            $jsnode["_"] = $textcontent;

        foreach ($xmlnode->children() as $childxmlnode) {
            $childname = $childxmlnode->getName();
            if (!array_key_exists($childname, $jsnode))
                $jsnode[$childname] = array();
            array_push($jsnode[$childname], xml2js($childxmlnode, true));
        }
        return $jsnode;
    } else {
        $nodename = $xmlnode->getName();
        $jsnode[$nodename] = array();
        array_push($jsnode[$nodename], xml2js($xmlnode, true));
        return json_encode($jsnode);
    }
}   

Exemple d'utilisation:

$xml = simplexml_load_file("myfile.xml");
echo xml2js($xml);

Exemple d'entrée (myfile.xml):

<family name="Johnson">
    <child name="John" age="5">
        <toy status="old">Trooper</toy>
        <toy status="old">Ultrablock</toy>
        <toy status="new">Bike</toy>
    </child>
</family>

Exemple de sortie:

{"family":[{"$":{"name":"Johnson"},"child":[{"$":{"name":"John","age":"5"},"toy":[{"$":{"status":"old"},"_":"Trooper"},{"$":{"status":"old"},"_":"Ultrablock"},{"$":{"status":"new"},"_":"Bike"}]}]}]}

Joli imprimé:

{
    "family" : [{
            "$" : {
                "name" : "Johnson"
            },
            "child" : [{
                    "$" : {
                        "name" : "John",
                        "age" : "5"
                    },
                    "toy" : [{
                            "$" : {
                                "status" : "old"
                            },
                            "_" : "Trooper"
                        }, {
                            "$" : {
                                "status" : "old"
                            },
                            "_" : "Ultrablock"
                        }, {
                            "$" : {
                                "status" : "new"
                            },
                            "_" : "Bike"
                        }
                    ]
                }
            ]
        }
    ]
}

Bizarreries à garder à l'esprit: plusieurs balises avec le même nom de variable peuvent être des frères et sœurs. D'autres solutions abandonneront probablement tout sauf le dernier frère. Pour éviter cela, chaque nœud, même s'il n'a qu'un seul enfant, est un tableau qui contient un objet pour chaque instance de la variable. (Voir plusieurs éléments "" dans l'exemple)

Même l'élément racine, dont un seul devrait exister dans un document XML valide, est stocké sous forme de tableau avec un objet de l'instance, juste pour avoir une structure de données cohérente.

Pour pouvoir faire la distinction entre le contenu du nœud XML et les attributs XML, les attributs de chaque objet sont stockés dans le "$" et le contenu dans l'enfant "_".

Edit: j'ai oublié d'afficher la sortie de votre exemple de données d'entrée

{
    "states" : [{
            "state" : [{
                    "$" : {
                        "id" : "AL"
                    },
                    "name" : [{
                            "_" : "Alabama"
                        }
                    ]
                }, {
                    "$" : {
                        "id" : "AK"
                    },
                    "name" : [{
                            "_" : "Alaska"
                        }
                    ]
                }
            ]
        }
    ]
}
FTav
la source
Peut-il analyser de grandes données XML?
Volatil3
2
Cette solution est meilleure car ne supprime pas les attributs XML. Voyez aussi pourquoi cette structure complexe est meilleure que les structures simplifiées, sur xml.com/lpt/a/1658 (voir "XML semi-structuré") .... Ops, pour CDATA, comme @txyoji l'a suggéré pour aplatir les éléments CDATA $xml = simplexml_load_file("myfile.xml",'SimpleXMLElement',LIBXML_‌​NOCDATA);.
Peter Krauss
Merci beaucoup pour une fonction personnalisée! Cela rend le réglage assez facile. Btw, a ajouté une version modifiée de votre fonction qui analyse le XML de manière JS: chaque entrée a son propre objet (les entrées ne sont pas stockées dans un seul tableau si elles ont des noms de variables égaux), donc l'ordre est conservé.
lucifer63
1
Erreur Fatal error: Uncaught Error: Call to a member function getName() on bool.. je pense qu'une version php est un échec :-( .. s'il vous plaît aider!
KingRider
10

Un écueil courant est d'oublier que json_encode()ne respecte pas les éléments avec une valeur de texte et un ou plusieurs attributs. Il en choisira un, signifiant dataloss. La fonction ci-dessous résout ce problème. Si l'on décide d'opter pour la voie json_encode/ decode, la fonction suivante est conseillée.

function json_prepare_xml($domNode) {
  foreach($domNode->childNodes as $node) {
    if($node->hasChildNodes()) {
      json_prepare_xml($node);
    } else {
      if($domNode->hasAttributes() && strlen($domNode->nodeValue)){
         $domNode->setAttribute("nodeValue", $node->textContent);
         $node->nodeValue = "";
      }
    }
  }
}

$dom = new DOMDocument();
$dom->loadXML( file_get_contents($xmlfile) );
json_prepare_xml($dom);
$sxml = simplexml_load_string( $dom->saveXML() );
$json = json_decode( json_encode( $sxml ) );

ce faisant, <foo bar="3">Lorem</foo>ne finira pas comme {"foo":"Lorem"}dans votre JSON.

Codeur du salut
la source
Ne compile pas et ne produit pas la sortie décrite si les erreurs de syntaxe sont corrigées.
Richard Kiefer
C'est quoi $dom? D'où vient cela?
Jake Wilson
$ dom = nouveau DOMDocument (); est d'où il vient
Scott
1
Dernière ligne de code: $ json = json_decode (json_encode ($ sxml))); devrait être: $ json = json_decode (json_encode ($ sxml));
Charlie Smith
6

Essayez d'utiliser ceci

$xml = ... // Xml file data

// first approach
$Json = json_encode(simplexml_load_string($xml));

---------------- OR -----------------------

// second approach
$Json = json_encode(simplexml_load_string($xml, "SimpleXMLElement", LIBXML_NOCDATA));

echo $Json;

Ou

Vous pouvez utiliser cette bibliothèque: https://github.com/rentpost/xml2array

Ajay Kumar
la source
3

J'ai utilisé le TypeConverter de Miles Johnson à cette fin. Il peut être installé à l'aide de Composer .

Vous pouvez écrire quelque chose comme ceci en l'utilisant:

<?php
require 'vendor/autoload.php';
use mjohnson\utility\TypeConverter;

$xml = file_get_contents("file.xml");
$arr = TypeConverter::xmlToArray($xml, TypeConverter::XML_GROUP);
echo json_encode($arr);
Rauque
la source
3

Optimisation de la réponse d'Antonio Max:

$xmlfile = 'yourfile.xml';
$xmlparser = xml_parser_create();

// open a file and read data
$fp = fopen($xmlfile, 'r');
//9999999 is the length which fread stops to read.
$xmldata = fread($fp, 9999999);

// converting to XML
$xml = simplexml_load_string($xmldata, "SimpleXMLElement", LIBXML_NOCDATA);

// converting to JSON
$json = json_encode($xml);
$array = json_decode($json,TRUE);
Marco Leuti
la source
4
J'ai utilisé cette approche, mais JSON est vide. XML est valide.
ryabenko-pro
2

Si vous souhaitez uniquement convertir une partie spécifique du XML en JSON, vous pouvez utiliser XPath pour le récupérer et le convertir en JSON.

<?php
$file = @file_get_contents($xml_File, FILE_TEXT);
$xml = new SimpleXMLElement($file);
$xml_Excerpt = @$xml->xpath('/states/state[@id="AL"]')[0]; // [0] gets the node
echo json_encode($xml_Excerpt);
?>

Veuillez noter que si votre Xpath est incorrect, cela mourra avec une erreur. Donc, si vous déboguez cela via des appels AJAX, je vous recommande de consigner également les corps de réponse.

ChrisR
la source
2
This is better solution

$fileContents= file_get_contents("https://www.feedforall.com/sample.xml");
$fileContents = str_replace(array("\n", "\r", "\t"), '', $fileContents);
$fileContents = trim(str_replace('"', "'", $fileContents));
$simpleXml = simplexml_load_string($fileContents);
$json = json_encode($simpleXml);
$array = json_decode($json,TRUE);
return $array;
Rashiqul Rony
la source
2

Meilleure solution qui fonctionne comme un charme

$fileContents= file_get_contents($url);

$fileContents = str_replace(array("\n", "\r", "\t"), '', $fileContents);

$fileContents = trim(str_replace('"', "'", $fileContents));

$simpleXml = simplexml_load_string($fileContents);

//$json = json_encode($simpleXml); // Remove // if you want to store the result in $json variable

echo '<pre>'.json_encode($simpleXml,JSON_PRETTY_PRINT).'</pre>';

La source

Alpha
la source
1

Il s'agit d'une amélioration de la solution la plus votée d'Antonio Max, qui fonctionne également avec XML qui a des espaces de noms (en remplaçant les deux points par un trait de soulignement). Il a également quelques options supplémentaires (et analyse <person my-attribute='name'>John</person>correctement).

function parse_xml_into_array($xml_string, $options = array()) {
    /*
    DESCRIPTION:
    - parse an XML string into an array
    INPUT:
    - $xml_string
    - $options : associative array with any of these keys:
        - 'flatten_cdata' : set to true to flatten CDATA elements
        - 'use_objects' : set to true to parse into objects instead of associative arrays
        - 'convert_booleans' : set to true to cast string values 'true' and 'false' into booleans
    OUTPUT:
    - associative array
    */

    // Remove namespaces by replacing ":" with "_"
    if (preg_match_all("|</([\\w\\-]+):([\\w\\-]+)>|", $xml_string, $matches, PREG_SET_ORDER)) {
        foreach ($matches as $match) {
            $xml_string = str_replace('<'. $match[1] .':'. $match[2], '<'. $match[1] .'_'. $match[2], $xml_string);
            $xml_string = str_replace('</'. $match[1] .':'. $match[2], '</'. $match[1] .'_'. $match[2], $xml_string);
        }
    }

    $output = json_decode(json_encode(@simplexml_load_string($xml_string, 'SimpleXMLElement', ($options['flatten_cdata'] ? LIBXML_NOCDATA : 0))), ($options['use_objects'] ? false : true));

    // Cast string values "true" and "false" to booleans
    if ($options['convert_booleans']) {
        $bool = function(&$item, $key) {
            if (in_array($item, array('true', 'TRUE', 'True'), true)) {
                $item = true;
            } elseif (in_array($item, array('false', 'FALSE', 'False'), true)) {
                $item = false;
            }
        };
        array_walk_recursive($output, $bool);
    }

    return $output;
}
TheStoryCoder
la source
2
On n'utilise pas Regex pour analyser XML, sauf s'il s'agit d'un simple XML avec une structure triviale et des données très prévisibles. Je ne saurais trop insister sur la gravité de cette solution. Ce BREAKS DATA. Sans parler du fait qu'il est incroyablement lent (vous analysez avec regex, puis vous re-analysez à nouveau?) Et ne gère pas les balises à fermeture automatique.
AlexanderMP
Je ne pense pas que vous ayez vraiment regardé la fonction. Il n'utilise pas regex pour faire l'analyse proprement dite, seulement comme une simple correction pour traiter les espaces de noms - qui a fonctionné pour tous mes cas xml - et que cela fonctionne est le plus important, plutôt que d'être "politiquement correct". Vous pouvez cependant l'améliorer si vous le souhaitez!
TheStoryCoder
2
Le fait que cela a fonctionné pour vous ne signifie pas que c'est juste. C'est un code comme celui-ci qui génère des bogues extrêmement difficiles à diagnostiquer et génère des exploits. Je veux dire que même en regardant superficiellement les spécifications XML sur des sites comme celui-ci w3schools.com/xml/xml_elements.asp montre de nombreuses raisons pour lesquelles cette solution ne fonctionnerait pas. Comme je l'ai dit, il ne détecte pas les balises à fermeture automatique comme <element/>, ne parvient pas à adresser les éléments qui commencent par ou contiennent des traits de soulignement, ce qui est autorisé dans XML. Ne parvient pas à détecter CDATA. Et comme je l'ai dit, c'est LENT. C'est une complexité O (n ^ 2) à cause de l'analyse interne.
AlexanderMP
1
Le fait est que le traitement des espaces de noms n'a même pas été demandé ici, et il existe des moyens appropriés pour gérer les espaces de noms. Les espaces de noms existent comme une construction utile, NE PAS être analysés comme ça et transformés en une abomination qui ne sera traitée par aucun analyseur raisonnable. Et tout ce que vous aviez à faire pour cela n'est pas de créer le candidat pour le prix de "l'algorithme le plus lent de 2016", mais de faire un peu de recherche, de trouver une myriade de solutions réelles, comme celle-ci stackoverflow.com/ questions / 16412047 /… Et pour appeler cela une amélioration? Sensationnel.
AlexanderMP
0

Toutes les solutions ici ont des problèmes!

... Lorsque la représentation nécessite une interprétation XML parfaite (sans problèmes d'attributs) et de reproduire tout le texte-tag-texte-tag-texte -... et l'ordre des balises. Rappelez-vous également ici que l' objet JSON "est un ensemble non ordonné" (pas de répétition des clés et les clés ne peuvent pas avoir un ordre prédéfini) ... Même le xml2json de ZF est faux (!) Car il ne conserve pas exactement la structure XML.

Toutes les solutions ici ont des problèmes avec ce XML simple,

    <states x-x='1'>
        <state y="123">Alabama</state>
        My name is <b>John</b> Doe
        <state>Alaska</state>
    </states>

... La solution @FTav semble meilleure que la solution 3 lignes, mais elle a aussi peu de bogue lorsqu'elle est testée avec ce XML.

L'ancienne solution est la meilleure (pour une représentation sans perte)

La solution, aujourd'hui connue sous le nom de jsonML , est utilisée par le projet Zorba et d'autres, et a été présentée pour la première fois en ~ 2006 ou ~ 2007, par (séparément) Stephen McKamey et John Snelson .

// the core algorithm is the XSLT of the "jsonML conventions"
// see  https://github.com/mckamey/jsonml
$xslt = 'https://raw.githubusercontent.com/mckamey/jsonml/master/jsonml.xslt';
$dom = new DOMDocument;
$dom->loadXML('
    <states x-x=\'1\'>
        <state y="123">Alabama</state>
        My name is <b>John</b> Doe
        <state>Alaska</state>
    </states>
');
if (!$dom) die("\nERROR!");
$xslDoc = new DOMDocument();
$xslDoc->load($xslt);
$proc = new XSLTProcessor();
$proc->importStylesheet($xslDoc);
echo $proc->transformToXML($dom);

Produire

["states",{"x-x":"1"},
    "\n\t    ",
    ["state",{"y":"123"},"Alabama"],
    "\n\t\tMy name is ",
    ["b","John"],
    " Doe\n\t    ",
    ["state","Alaska"],
    "\n\t"
]

Voir http://jsonML.org ou github.com/mckamey/jsonml . Les règles de production de ce JSON sont basées sur l' élément JSON-analogique,

entrez la description de l'image ici

Cette syntaxe est une définition d' élément et une récurrence, avec
element-list ::= element ',' element-list | element.

Peter Krauss
la source
2
Une structure XML très inhabituelle qui, je doute, aurait des cas d'utilisation réels.
TheStoryCoder
0

Après avoir recherché un peu toutes les réponses, j'ai trouvé une solution qui fonctionnait très bien avec mes fonctions JavaScript sur tous les navigateurs (y compris les consoles / outils de développement):

<?php

 // PHP Version 7.2.1 (Windows 10 x86)

 function json2xml( $domNode ) {
  foreach( $domNode -> childNodes as $node) {
   if ( $node -> hasChildNodes() ) { json2xml( $node ); }
   else {
    if ( $domNode -> hasAttributes() && strlen( $domNode -> nodeValue ) ) {
     $domNode -> setAttribute( "nodeValue", $node -> textContent );
     $node -> nodeValue = "";
    }
   }
  }
 }

 function jsonOut( $file ) {
  $dom = new DOMDocument();
  $dom -> loadXML( file_get_contents( $file ) );
  json2xml( $dom );
  header( 'Content-Type: application/json' );
  return str_replace( "@", "", json_encode( simplexml_load_string( $dom -> saveXML() ), JSON_PRETTY_PRINT ) );
 }

 $output = jsonOut( 'https://boxelizer.com/assets/a1e10642e9294f39/b6f30987f0b66103.xml' );

 echo( $output );

 /*
  Or simply 
  echo( jsonOut( 'https://boxelizer.com/assets/a1e10642e9294f39/b6f30987f0b66103.xml' ) );
 */

?>

Il crée essentiellement un nouveau DOMDocument, y charge un fichier XML et parcourt chacun des nœuds et des enfants en récupérant les données / paramètres et en les exportant en JSON sans les signes "@" ennuyeux.

Lien vers le fichier XML .

Xedret
la source
0

Cette solution gère les espaces de noms, les attributs et produit un résultat cohérent avec des éléments répétitifs (toujours dans un tableau, même s'il n'y a qu'une seule occurrence). Inspiré par sxiToArray () de ratfactor .

/**
 * <root><a>5</a><b>6</b><b>8</b></root> -> {"root":[{"a":["5"],"b":["6","8"]}]}
 * <root a="5"><b>6</b><b>8</b></root> -> {"root":[{"a":"5","b":["6","8"]}]}
 * <root xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"><a>123</a><wsp:b>456</wsp:b></root> 
 *   -> {"root":[{"xmlns:wsp":"http://schemas.xmlsoap.org/ws/2004/09/policy","a":["123"],"wsp:b":["456"]}]}
 */
function domNodesToArray(array $tags, \DOMXPath $xpath)
{
    $tagNameToArr = [];
    foreach ($tags as $tag) {
        $tagData = [];
        $attrs = $tag->attributes ? iterator_to_array($tag->attributes) : [];
        $subTags = $tag->childNodes ? iterator_to_array($tag->childNodes) : [];
        foreach ($xpath->query('namespace::*', $tag) as $nsNode) {
            // the only way to get xmlns:*, see https://stackoverflow.com/a/2470433/2750743
            if ($tag->hasAttribute($nsNode->nodeName)) {
                $attrs[] = $nsNode;
            }
        }

        foreach ($attrs as $attr) {
            $tagData[$attr->nodeName] = $attr->nodeValue;
        }
        if (count($subTags) === 1 && $subTags[0] instanceof \DOMText) {
            $text = $subTags[0]->nodeValue;
        } elseif (count($subTags) === 0) {
            $text = '';
        } else {
            // ignore whitespace (and any other text if any) between nodes
            $isNotDomText = function($node){return !($node instanceof \DOMText);};
            $realNodes = array_filter($subTags, $isNotDomText);
            $subTagNameToArr = domNodesToArray($realNodes, $xpath);
            $tagData = array_merge($tagData, $subTagNameToArr);
            $text = null;
        }
        if (!is_null($text)) {
            if ($attrs) {
                if ($text) {
                    $tagData['_'] = $text;
                }
            } else {
                $tagData = $text;
            }
        }
        $keyName = $tag->nodeName;
        $tagNameToArr[$keyName][] = $tagData;
    }
    return $tagNameToArr;
}

function xmlToArr(string $xml)
{
    $doc = new \DOMDocument();
    $doc->loadXML($xml);
    $xpath = new \DOMXPath($doc);
    $tags = $doc->childNodes ? iterator_to_array($doc->childNodes) : [];
    return domNodesToArray($tags, $xpath);
}

Exemple:

php > print(json_encode(xmlToArr('<root a="5"><b>6</b></root>')));
{"root":[{"a":"5","b":["6"]}]}
Klesun
la source
cela fonctionne réellement pour les cas multi-espaces de noms, mieux que les autres solutions, pourquoi a-t-il voté contre ...
aaron
0

J'ai trouvé la réponse de FTav la plus utile car elle est très personnalisable, mais sa fonction xml2js présente quelques défauts. Par exemple, si les éléments enfants ont des noms de variables égaux, ils seront tous stockés dans un seul objet, cela signifie que l'ordre des éléments ne sera pas conservé. Dans certains cas, nous voulons vraiment préserver l'ordre, il vaut donc mieux stocker les données de chaque élément dans un objet séparé:

function xml2js($xmlnode) {
    $jsnode = array();
    $nodename = $xmlnode->getName();
    $current_object = array();

    if (count($xmlnode->attributes()) > 0) {
        foreach($xmlnode->attributes() as $key => $value) {
            $current_object[$key] = (string)$value;
        }
    }

    $textcontent = trim((string)$xmlnode);
    if (strlen($textcontent) > 0) {
        $current_object["content"] = $textcontent;
    }

    if (count($xmlnode->children()) > 0) {
        $current_object['children'] = array();
        foreach ($xmlnode->children() as $childxmlnode) {
            $childname = $childxmlnode->getName();
            array_push($current_object['children'], xml2js($childxmlnode, true));
        }
    }

    $jsnode[ $nodename ] = $current_object;
    return $jsnode;
}

Voici comment cela fonctionne. Structure xml initiale:

<some-tag some-attribute="value of some attribute">
  <another-tag>With text</another-tag>
  <surprise></surprise>
  <another-tag>The last one</another-tag>
</some-tag>

Résultat JSON:

{
    "some-tag": {
        "some-attribute": "value of some attribute",
        "children": [
            {
                "another-tag": {
                    "content": "With text"
                }
            },
            {
                "surprise": []
            },
            {
                "another-tag": {
                    "content": "The last one"
                }
            }
        ]
    }
}
lucifer63
la source
-1

On dirait que la $state->namevariable contient un tableau. Vous pouvez utiliser

var_dump($state)

à l'intérieur du foreachpour tester cela.

Si tel est le cas, vous pouvez modifier la ligne à l' intérieur du foreachà

$states[]= array('state' => array_shift($state->name)); 

pour le corriger.

Michael Fenwick
la source
on dirait que les attributs sont des tableaux mais pas $ state-> name
Bryan Hadlock
-1
$templateData =  $_POST['data'];

// initializing or creating array
$template_info =  $templateData;

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

// function call to convert array to xml
array_to_xml($template_info,$xml_template_info);

//saving generated xml file
 $xml_template_info->asXML(dirname(__FILE__)."/manifest.xml") ;

// function defination to convert array to xml
function array_to_xml($template_info, &$xml_template_info) {
    foreach($template_info as $key => $value) {
        if(is_array($value)) {
            if(!is_numeric($key)){
                $subnode = $xml_template_info->addChild($key);
                if(is_array($value)){
                    $cont = 0;
                    foreach(array_keys($value) as $k){
                        if(is_numeric($k)) $cont++;
                    }
                }

                if($cont>0){
                    for($i=0; $i < $cont; $i++){
                        $subnode = $xml_body_info->addChild($key);
                        array_to_xml($value[$i], $subnode);
                    }
                }else{
                    $subnode = $xml_body_info->addChild($key);
                    array_to_xml($value, $subnode);
                }
            }
            else{
                array_to_xml($value, $xml_template_info);
            }
        }
        else {
            $xml_template_info->addChild($key,$value);
        }
    }
}
Octavio Perez Gallegos
la source
C'est une petite solution universelle basée sur un tableau de données qui peut être un JSON transformé json_decode ... lucky
Octavio Perez Gallegos
2
En quoi cela répond-il à la question initiale? Votre réponse semble plus compliquée que la question originale et ne semble même pas mentionner JSON nulle part.
Dan R
-1

Si vous êtes un utilisateur ubuntu, installez le lecteur xml (j'ai php 5.6.Si vous en avez d'autres, veuillez trouver le package et l'installer)

sudo apt-get install php5.6-xml
service apache2 restart

$fileContents = file_get_contents('myDirPath/filename.xml');
$fileContents = str_replace(array("\n", "\r", "\t"), '', $fileContents);
$fileContents = trim(str_replace('"', "'", $fileContents));
$oldXml = $fileContents;
$simpleXml = simplexml_load_string($fileContents);
$json = json_encode($simpleXml);
Atul Baldaniya
la source