PHP mengonversi XML ke JSON

158

Saya mencoba mengonversi xml ke json di php. Jika saya melakukan konversi sederhana menggunakan xml sederhana dan json_encode tidak ada atribut di acara xml.

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

Jadi saya mencoba menguraikannya secara manual seperti ini.

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

dan output untuk negara {"state":{"0":"Alabama"}}bukan{"state":"Alabama"}

Apa yang saya lakukan salah?

XML:

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

Keluaran:

[{"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
sumber
Harap sertakan cuplikan XML dan struktur susunan akhir yang Anda miliki setelah menguraikannya. (A var_dumpberfungsi dengan baik.)
nikc.org
menambahkan input, output, dan var_dump
Bryan Hadlock
Beberapa aplikasi memerlukan "peta XML-to-JSON perfec" , yaitu jsonML , lihat solusinya di sini .
Peter Krauss

Jawaban:

473

Json & Array dari XML dalam 3 baris:

$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
Antonio Max
sumber
59
Solusi ini tidak sempurna. Ini benar-benar membuang atribut XML. Jadi <person my-attribute='name'>John</person>diartikan sebagai <person>John</person>.
Jake Wilson
13
$ xml = simplexml_load_string ($ xml_string, 'SimpleXMLElement', LIBXML_NOCDATA); untuk meratakan elemen cdata.
txyoji
28
@JakeWilson mungkin 2 tahun yang telah berlalu, dan berbagai perbaikan versi, tetapi pada PHP 5.6.30, metode ini menghasilkan SEMUA data. Atribut disimpan dalam array di bawah @attributeskunci, sehingga berfungsi dengan sempurna, dan indah. 3 baris pendek kode memecahkan masalah saya dengan indah.
AlexanderMP
1
Ini tidak berfungsi jika Anda memiliki beberapa ruang nama, Anda hanya dapat memilih satu, yang akan masuk ke $ json_string: '(
jirislav
1
Perlu diingat bahwa dengan solusi ini, ketika mungkin ada beberapa node dengan nama yang sama, satu node akan menghasilkan kunci yang hanya menunjuk ke suatu elemen, tetapi beberapa node akan menghasilkan kunci yang menunjuk ke array elemen: <list><item><a>123</a><a>456</a></item><item><a>123</a></item></list>-> {"item":[{"a":["123","456"]},{"a":"123"}]}. Solusi di php.net oleh ratfactor memecahkan masalah itu dengan selalu menyimpan elemen dalam array.
Klesun
37

Maaf telah menjawab kiriman lama, tetapi artikel ini menguraikan pendekatan yang relatif singkat, ringkas, dan mudah dikelola. Saya mengujinya sendiri dan bekerja dengan cukup baik.

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
sumber
4
Ini tidak akan berfungsi jika Anda memiliki beberapa instance dari tag yang sama di XML Anda, json_encode hanya akan berakhir dengan membuat serial contoh terakhir dari tag tersebut.
ethree
35

Saya menemukan jawabannya. json_encode menangani objek secara berbeda dari string. Saya melemparkan objek ke string dan berfungsi sekarang.

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

Saya kira saya agak terlambat ke pesta tetapi saya telah menulis fungsi kecil untuk menyelesaikan tugas ini. Ini juga menangani atribut, konten teks dan bahkan jika beberapa node dengan nama simpul yang sama adalah saudara kandung.

Penafian: Saya bukan orang asli PHP, jadi mohon lakukan kesalahan sederhana.

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

Contoh penggunaan:

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

Input Contoh (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>

Contoh output:

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

Cukup dicetak:

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

Yang perlu diingat: Beberapa tag dengan tagname yang sama dapat berupa saudara kandung. Solusi lain kemungkinan besar akan menjatuhkan semua kecuali saudara terakhir. Untuk menghindari hal ini, setiap simpul tunggal, meskipun hanya memiliki satu anak, adalah larik yang menyimpan objek untuk setiap instance tagname. (Lihat beberapa elemen "" sebagai contoh)

Bahkan elemen root, yang hanya ada satu di dokumen XML yang valid disimpan sebagai array dengan objek instance, hanya untuk memiliki struktur data yang konsisten.

Agar dapat membedakan antara konten simpul XML dan atribut XML, setiap atribut obyek disimpan dalam "$" dan konten pada anak "_".

Sunting: Saya lupa menampilkan output untuk data input contoh Anda

{
    "states" : [{
            "state" : [{
                    "$" : {
                        "id" : "AL"
                    },
                    "name" : [{
                            "_" : "Alabama"
                        }
                    ]
                }, {
                    "$" : {
                        "id" : "AK"
                    },
                    "name" : [{
                            "_" : "Alaska"
                        }
                    ]
                }
            ]
        }
    ]
}
FTav
sumber
Bisakah itu menguraikan data XML besar?
Volatil3
2
Solusi ini lebih baik karena tidak membuang atribut XML. Lihat juga mengapa struktur kompleks ini lebih baik daripada yang disederhanakan, di xml.com/lpt/a/1658 (lihat "XML Semi-Terstruktur") .... Ops, untuk CDATA, seperti yang disarankan oleh @txyoji untuk meratakan elemen-elemen CDATA $xml = simplexml_load_file("myfile.xml",'SimpleXMLElement',LIBXML_‌​NOCDATA);.
Peter Krauss
Terima kasih banyak atas fungsi khusus! Itu membuat tuning cukup mudah. Btw, menambahkan versi yang diedit dari fungsi Anda yang mem-parsing XML dengan cara JS: setiap entri memiliki objeknya sendiri (entri tidak disimpan dalam array tunggal jika mereka memiliki nama-nama yang sama), sehingga urutannya dipertahankan.
lucifer63
1
Kesalahan Fatal error: Uncaught Error: Call to a member function getName() on bool.. saya pikir versi php gagal :-( .. tolong bantu!
KingRider
10

Jebakan yang umum adalah melupakan yang json_encode()tidak menghargai elemen dengan nilai teks dan atribut. Ini akan memilih salah satunya, yang berarti dataloss. Fungsi di bawah menyelesaikan masalah itu. Jika seseorang memutuskan untuk menggunakan json_encode/ decodeway, fungsi berikut disarankan.

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

dengan melakukan itu, <foo bar="3">Lorem</foo>tidak akan berakhir seperti {"foo":"Lorem"}pada JSON Anda.

Coder Of Salvation
sumber
Tidak mengkompilasi dan tidak menghasilkan output yang dijelaskan jika kesalahan sintaks diperbaiki.
Richard Kiefer
Apa $dom? Darimana itu datang?
Jake Wilson
$ dom = DOMDocument baru (); adalah tempat asalnya
Scott
1
Baris kode terakhir: $ json = json_decode (json_encode ($ sxml)))); seharusnya: $ json = json_decode (json_encode ($ sxml));
Charlie Smith
6

Coba gunakan ini

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

Atau

Anda dapat menggunakan perpustakaan ini: https://github.com/rentpost/xml2array

Ajay Kumar
sumber
3

Saya telah menggunakan TypeConverter Miles Johnson untuk tujuan ini. Dapat diinstal menggunakan Komposer .

Anda dapat menulis sesuatu seperti ini dengan menggunakannya:

<?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);
Serak
sumber
3

Mengoptimalkan jawaban 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
sumber
4
Saya menggunakan pendekatan ini, tetapi JSON kosong. XML valid.
ryabenko-pro
2

Jika Anda hanya ingin mengonversi bagian tertentu dari XML ke JSON, Anda dapat menggunakan XPath untuk mengambil ini dan mengonversinya menjadi 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);
?>

Harap dicatat bahwa jika Anda Xpath salah, ini akan mati dengan kesalahan. Jadi, jika Anda men-debug ini melalui panggilan AJAX, saya sarankan Anda juga mencatat badan respons.

ChrisR
sumber
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
sumber
2

Solusi terbaik yang berfungsi seperti pesona

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

Sumber

Alfa
sumber
1

Ini merupakan peningkatan dari solusi yang paling banyak dipilih oleh Antonio Max, yang juga bekerja dengan XML yang memiliki ruang nama (dengan mengganti titik dua dengan garis bawah). Ini juga memiliki beberapa opsi tambahan (dan tidak menguraikan <person my-attribute='name'>John</person>dengan benar).

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
sumber
2
Seseorang tidak menggunakan Regex untuk mem-parsing XML, kecuali itu adalah XML sederhana dengan struktur sepele dan data yang sangat mudah diprediksi. Saya tidak bisa cukup menekankan betapa buruknya solusi ini. BREAKS DATA ini. Belum lagi itu sangat lambat (Anda parse dengan regex, dan kemudian Anda parse lagi?) Dan tidak menangani tag yang menutup sendiri.
AlexanderMP
Saya tidak berpikir Anda benar-benar melihat fungsinya. Itu tidak menggunakan regex untuk melakukan penguraian yang sebenarnya, hanya sebagai perbaikan sederhana untuk menangani ruang nama - yang telah bekerja untuk semua kasus xml saya - dan itu berfungsi adalah yang paling penting, daripada menjadi "benar secara politis". Anda dipersilakan untuk memperbaikinya jika Anda mau!
TheStoryCoder
2
Fakta bahwa itu berhasil untuk Anda bukan berarti itu benar. Kode seperti ini yang menghasilkan bug yang sangat sulit didiagnosis, dan menghasilkan exploit. Maksud saya, bahkan melihat secara dangkal spesifikasi XML di situs-situs seperti ini w3schools.com/xml/xml_elements.asp menunjukkan banyak alasan mengapa solusi ini tidak berfungsi. Seperti yang saya katakan, gagal mendeteksi tag penutup diri seperti <element/>, gagal untuk mengatasi elemen yang dimulai dengan, atau berisi garis bawah, yang diizinkan dalam XML. Gagal mendeteksi CDATA. Dan seperti yang sudah saya katakan, ini PERLAHAN. Ini adalah kompleksitas O (n ^ 2) karena penguraian dalam.
AlexanderMP
1
Masalahnya adalah bahwa berurusan dengan ruang nama bahkan tidak ditanyakan di sini, dan ada cara yang lebih baik untuk berurusan dengan ruang nama. Namespaces ada sebagai konstruksi bermanfaat, BUKAN diurai seperti itu dan berubah menjadi kekejian yang tidak akan diproses oleh pengurai yang masuk akal. Dan semua yang perlu Anda lakukan untuk itu bukan untuk menciptakan pesaing untuk hadiah "algoritma paling lambat 2016", tetapi untuk melakukan sedikit pencarian, untuk datang dengan segudang solusi aktual, seperti ini stackoverflow.com/ pertanyaan / 16412047 / ... Dan menyebutnya perbaikan? Wow.
AlexanderMP
0

Semua solusi di sini memiliki masalah!

... Ketika representasi memerlukan interpretasi XML yang sempurna (tanpa masalah dengan atribut) dan untuk mereproduksi semua tag-teks-tag-teks-teks -... dan urutan tag. Juga baik diingat di sini bahwa objek JSON "adalah set unordered" (tidak mengulangi kunci dan kunci tidak dapat memiliki urutan yang telah ditentukan) ... Bahkan xml2json ZF salah (!) Karena tidak mempertahankan persis struktur XML.

Semua solusi di sini memiliki masalah dengan XML sederhana ini,

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

... @FTav solusi tampaknya lebih baik daripada solusi 3-line, tetapi juga memiliki sedikit bug ketika diuji dengan XML ini.

Solusi lama adalah yang terbaik (untuk representasi loss-less)

Solusinya, hari ini dikenal sebagai jsonML , digunakan oleh proyek Zorba dan lainnya, dan pertama kali disajikan pada ~ 2006 atau ~ 2007, oleh (secara terpisah) Stephen McKamey dan 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);

Menghasilkan

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

Lihat http://jsonML.org atau github.com/mckamey/jsonml . Aturan produksi JSON ini didasarkan pada elemen JSON-analog,

masukkan deskripsi gambar di sini

Sintaks ini adalah definisi elemen dan pengulangan, dengan
element-list ::= element ',' element-list | element.

Peter Krauss
sumber
2
Struktur xml yang sangat tidak biasa yang saya ragu akan menggunakan case nyata.
TheStoryCoder
0

Setelah meneliti sedikit dari semua jawaban, saya datang dengan solusi yang berfungsi dengan baik dengan fungsi JavaScript saya di seluruh browser (Termasuk konsol / Perangkat 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' ) );
 */

?>

Ini pada dasarnya membuat DOMDocument baru, memuat dan file XML ke dalamnya dan melintasi setiap node dan anak-anak mendapatkan data / parameter dan mengekspornya ke JSON tanpa tanda "@" yang mengganggu.

Tautan ke file XML .

Xedret
sumber
0

Solusi ini menangani ruang nama, atribut, dan menghasilkan hasil yang konsisten dengan elemen berulang (selalu dalam array, bahkan jika hanya ada satu kejadian). Terinspirasi oleh sxiToArray 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);
}

Contoh:

php > print(json_encode(xmlToArr('<root a="5"><b>6</b></root>')));
{"root":[{"a":"5","b":["6"]}]}
Klesun
sumber
ini benar-benar berfungsi untuk kasus multi-namespace, lebih baik daripada solusi lain, mengapa mendapat suara turun ...
aaron
0

Menemukan jawaban FTav yang paling berguna karena sangat dapat disesuaikan, tetapi fungsi xml2js- nya memiliki beberapa kelemahan. Sebagai contoh, jika elemen anak-anak memiliki tagnames yang sama mereka semua akan disimpan dalam satu objek, ini berarti bahwa urutan elemen tidak akan dipertahankan. Dalam beberapa kasus, kami benar-benar ingin mempertahankan pesanan, jadi sebaiknya kami menyimpan data setiap elemen dalam objek terpisah:

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

Inilah cara kerjanya. Struktur xml awal:

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

JSON hasil:

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

Sepertinya $state->namevariabel memegang array. Kamu bisa memakai

var_dump($state)

di dalam foreachuntuk menguji itu.

Jika itu masalahnya, Anda dapat mengubah garis di dalam foreachke

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

untuk memperbaikinya.

Michael Fenwick
sumber
sepertinya atributnya adalah array tetapi bukan $ 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
sumber
Ini adalah solusi kecil dan universal berdasarkan pada array data yang dapat diubah JSON json_decode ... lucky
Octavio Perez Gallegos
2
Dengan cara apa ini menjawab pertanyaan awal? Jawaban Anda tampaknya lebih rumit daripada pertanyaan awal, dan juga sepertinya tidak menyebutkan JSON di mana pun.
Dan R
-1

Jika Anda pengguna ubuntu, instal xml reader (saya punya php 5.6. Jika Anda punya yang lain, silakan cari paket dan instal)

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
sumber