PHP converter XML para JSON

estou a tentar converter xml para json em php. Se eu fizer um simples convert usando xml simples e json_ encode nenhum dos atributos no xml show.

$xml = simplexml_load_file("states.xml");
echo json_encode($xml);
Estou a tentar analisá-lo manualmente.

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

e a saída para o estado é {"state":{"0":"Alabama"}} em vez de {"state":"Alabama"}

O que estou a fazer de errado?

XML:

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

resultado:

[{"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"
}
}
}
 113
Author: Bryan Hadlock, 2012-01-12

16 answers

Lista Json do XML em 3 linhas:

$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
Ta da!
 358
Author: Antonio Max, 2013-10-15 21:36:26

Desculpe por responder a um post antigo, mas este artigo descreve uma abordagem que é relativamente curta, concisa e fácil de manter. Eu mesmo testei e funciona muito bem.

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;
    }
}
?>
 34
Author: Coreus, 2013-03-11 09:47:24
Eu descobri. json_encode lida com objetos de forma diferente de strings. Eu lancei o objecto a uma corda e funciona agora.
foreach($xml->children() as $state)
{
    $states[]= array('state' => (string)$state->name); 
}       
echo json_encode($states);
 28
Author: Bryan Hadlock, 2012-01-13 03:56:20
Acho que estou um pouco atrasado para a festa, mas escrevi uma pequena função para cumprir esta tarefa. Ele também cuida de atributos, conteúdo de texto e mesmo se múltiplos nós com o mesmo nome de nó são irmãos.

Dissaimer: Eu não sou um nativo do PHP, assim que por favor tenha com erros simples.

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

Exemplo de Utilização:

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

Exemplo de entrada (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>

Exemplo de saída:

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

Bonita. impresso:

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

Peculiaridades para ter em mente: Vários tags com o mesmo tamanhame podem ser irmãos. Outras soluções irão provavelmente cair todas menos o último irmão. Para evitar isso, cada nó, mesmo que tenha apenas um filho, é um array que contém um objeto para cada instância do diagnóstico. (Ver múltiplos elementos "" no exemplo)

Mesmo o elemento root, do qual apenas um deve existir num documento XML válido é armazenado como array com um objecto do exemplo, só para ter uma estrutura de dados consistente.

Para ser capaz de distinguir entre o conteúdo do nó XML e atributos XML cada atributos de objetos são armazenados no "$" e o conteúdo na criança"_".

Editar: Esqueci-me de mostrar o resultado dos dados de entrada.

{
    "states" : [{
            "state" : [{
                    "$" : {
                        "id" : "AL"
                    },
                    "name" : [{
                            "_" : "Alabama"
                        }
                    ]
                }, {
                    "$" : {
                        "id" : "AK"
                    },
                    "name" : [{
                            "_" : "Alaska"
                        }
                    ]
                }
            ]
        }
    ]
}
 15
Author: FTav, 2015-06-09 13:14:04

Tente usar este

$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

Pode usar esta biblioteca: https://github.com/rentpost/xml2array

 6
Author: Ajay Kumar, 2017-09-05 20:11:29

Uma armadilha comum é esquecer que json_encode() não respeita elementos com um textvalue e Atributos. Vai escolher um desses, ou seja, dataloss. A função abaixo resolve esse problema. Se alguém decidir ir para o json_encode/decode assim, a seguinte função é aconselhada.

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 ) );
Ao fazê-lo, <foo bar="3">Lorem</foo> não vai acabar como {"foo":"Lorem"} no teu JSON.
 5
Author: Coder Of Salvation, 2017-06-08 04:43:53

A optimizar a resposta do 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);
 4
Author: Marco Leuti, 2017-10-18 08:16:01
Usei o TypeConverter do Miles Johnson para este fim. É instalável usando O compositor . Podes escrever algo assim usando-o:
<?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);
 3
Author: Husky, 2013-05-29 13:59:08

Esta é uma melhoria da solução mais votada por Antonio Max, que também trabalha com XML que tem espaços de nomes (substituindo o cólon por um sublinhado). Ele também tem algumas opções extras (e faz processar <person my-attribute='name'>John</person> corretamente).

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;
}
 2
Author: TheStoryCoder, 2016-11-30 09:31:28

Se quiser converter apenas uma parte específica do XML para JSON, pode usar o XPath para recuperar isto e convertê-lo para 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);
?>

Por favor, note que se o Xpath estiver incorrecto, isto irá morrer com um erro. Por isso, se está a debugar isto através das chamadas do AJAX, recomendo que registe os corpos de resposta também.

 1
Author: ChrisR, 2013-08-27 13:15:40

Parece que a variável $state->name tem uma matriz. Pode utilizar

var_dump($state)

Dentro do foreach para testar isso.

Se for esse o caso, pode mudar a linha dentro do foreach para
$states[]= array('state' => array_shift($state->name)); 
Para corrigi-lo.
 0
Author: Michael Fenwick, 2012-01-12 05:46:52

A pergunta não o diz, mas normalmente o PHP está a devolver o JSON a uma página web.

Acho muito mais fácil converter o XML para JSON no navegador/página através de uma js lib, por exemplo:

https://code.google.com/p/x2js/downloads/detail?name=x2js-v1.1.3.zip
 0
Author: Bret Weinraub, 2013-12-05 15:27:05
Todas as soluções aqui têm problemas!

... Quando a representação precisa de interpretação XML perfeita (sem problemas com atributos) e para reproduzir todo texto-tag-text-tag-text-text -... e a ordem das etiquetas. Também é bom lembrar aqui que o objecto JSON "é um conjunto não ordenado" (não repetir as teclas e as teclas não podem ter uma ordem predefinida)... Mesmo O XML2JSON de ZF está errado (!) porque não preservar exatamente a estrutura XML.

Todas as soluções aqui têm problemas com este XML simples,
    <states x-x='1'>
        <state y="123">Alabama</state>
        My name is <b>John</b> Doe
        <state>Alaska</state>
    </states>

... @FTav solução parece melhor do que Solução de 3 linhas, mas também tem pouco bug quando testado com este XML.

A solução antiga é a melhor (para representação menos perdas)

A solução, hoje conhecido como jsonML, é utilizada por Zorba projeto e outros, e foi apresentado pela primeira vez em ~2006 ~2007, pelo (separadamente) Stephen McKamey e 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);

Produzir

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

Ver http://jsonML.org ou github.com/mckamey/jsonml as regras de produção deste JSON baseiam - se no elemento JSON-analógico,

enter image description here

Esta sintaxe é um elemento definição e recorrência, com
element-list ::= element ',' element-list | element.

 0
Author: Peter Krauss, 2016-10-06 13:26:55
$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);

Basta adicionar essas três linhas e obterá a saída correcta: -)

 0
Author: karthik, 2018-04-26 05:46:08

Depois de pesquisar um pouco todas as respostas, arranjei uma solução que funcionou muito bem com as minhas funções JavaScript nos navegadores (incluindo consoles / Ferramentas Dev):

<?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' ) );
 */

?>
Ele basicamente cria um novo arquivo DOMDocument, carrega e XML nele e atravessa através de cada um dos nós e crianças obtendo os dados / parâmetros e exportando-o para JSON sem os sinais irritantes"@".

Ligação ao ficheiro XML .

 0
Author: Xedret, 2018-07-06 00:08:02
$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);
        }
    }
}
 -1
Author: Octavio Perez Gallegos, 2016-06-30 22:43:08