PHP konwertuje XML na JSON

158

Próbuję przekonwertować xml na json w php. Jeśli wykonam prostą konwersję przy użyciu prostego kodu XML i json_encode, żaden z atrybutów w pokazie XML.

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

Więc próbuję ręcznie przeanalizować to w ten sposób.

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

a wyjście dla stanu to {"state":{"0":"Alabama"}}raczej niż{"state":"Alabama"}

Co ja robię źle?

XML:

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

Wynik:

[{"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
źródło
Dołącz fragment kodu XML i ostateczną strukturę tablicy, którą masz po jego przeanalizowaniu. (A var_dumpdziała dobrze.)
nikc.org
dodane wejście, wyjście i var_dump
Bryan Hadlock
Niektóre aplikacje wymagają „perfec XML-to-JSON map” , czyli jsonML , zobacz rozwiązanie tutaj .
Peter Krauss

Odpowiedzi:

472

Json & Array z XML w 3 liniach:

$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
Antonio Max
źródło
58
To rozwiązanie nie jest bezbłędne. Całkowicie odrzuca atrybuty XML. Tak <person my-attribute='name'>John</person>jest interpretowane jako <person>John</person>.
Jake Wilson
13
$ xml = simplexml_load_string ($ xml_string, 'SimpleXMLElement', LIBXML_NOCDATA); spłaszczyć elementy cdata.
txyoji
28
@JakeWilson może minęły 2 lata i różne wersje poprawek, ale w PHP 5.6.30 ta metoda generuje WSZYSTKIE dane. Atrybuty są przechowywane w tablicy pod @attributeskluczem, więc działa absolutnie bezbłędnie i pięknie. 3 krótkie linijki kodu pięknie rozwiązują mój problem.
AlexanderMP,
1
To nie działa, jeśli masz wiele przestrzeni nazw, możesz wybrać tylko jedną, która przejdzie do $ json_string: '(
jirislav
1
Należy pamiętać, że w przypadku tego rozwiązania, gdy może istnieć wiele węzłów o tej samej nazwie, jeden węzeł będzie skutkował kluczem wskazującym tylko na element, ale wiele węzłów spowoduje, że klucz wskaże tablicę elementów: <list><item><a>123</a><a>456</a></item><item><a>123</a></item></list>-> {"item":[{"a":["123","456"]},{"a":"123"}]}. Rozwiązanie na php.net autorstwa ratfactor rozwiązuje ten problem, zawsze przechowując elementy w tablicy.
Klesun,
37

Przepraszamy, że odpowiadam na stary post, ale ten artykuł przedstawia podejście, które jest stosunkowo krótkie, zwięzłe i łatwe w utrzymaniu. Sam to przetestowałem i działa całkiem nieźle.

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
źródło
4
To nie zadziała, jeśli masz wiele wystąpień tego samego tagu w swoim kodzie XML, json_encode spowoduje serializowanie tylko ostatniej instancji tagu.
etree
35

Rozgryzłem to. json_encode obsługuje obiekty inaczej niż ciągi. Rzuciłem obiekt na strunę i teraz działa.

foreach($xml->children() as $state)
{
    $states[]= array('state' => (string)$state->name); 
}       
echo json_encode($states);
Bryan Hadlock
źródło
19

Chyba trochę się spóźniłem na przyjęcie, ale napisałem małą funkcję, aby wykonać to zadanie. Dba również o atrybuty, zawartość tekstową, a nawet jeśli wiele węzłów o tej samej nazwie węzła jest rodzeństwem.

Zastrzeżenie: nie jestem natywnym językiem PHP, więc proszę, znoszę proste błędy.

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

Przykład użycia:

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

Przykładowe dane wejściowe (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>

Przykładowe dane wyjściowe:

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

Całkiem wydrukowane:

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

Dziwactwa, o których należy pamiętać: kilka tagów z tą samą zmienną może być rodzeństwem. Inne rozwiązania najprawdopodobniej odrzucą wszystko oprócz ostatniego rodzeństwa. Aby tego uniknąć, każdy węzeł, nawet jeśli ma tylko jedno dziecko, jest tablicą przechowującą obiekt dla każdej instancji zmiennej. (Zobacz przykład wielu elementów „”)

Nawet element główny, z którego tylko jeden powinien istnieć w ważnym dokumencie XML, jest przechowywany jako tablica z obiektem instancji, aby mieć spójną strukturę danych.

Aby móc odróżnić zawartość węzła XML od atrybutów XML, każdy atrybut obiektu jest przechowywany w „$”, a zawartość w podrzędnym „_”.

Edycja: zapomniałem pokazać dane wyjściowe dla przykładowych danych wejściowych

{
    "states" : [{
            "state" : [{
                    "$" : {
                        "id" : "AL"
                    },
                    "name" : [{
                            "_" : "Alabama"
                        }
                    ]
                }, {
                    "$" : {
                        "id" : "AK"
                    },
                    "name" : [{
                            "_" : "Alaska"
                        }
                    ]
                }
            ]
        }
    ]
}
FTav
źródło
Czy może analizować duże dane XML?
Volatil3
2
To rozwiązanie jest lepsze, ponieważ nie odrzuca atrybutów XML. Zobacz także, dlaczego ta złożona struktura jest lepsza niż uproszczona, na xml.com/lpt/a/1658 (zobacz "Semi-Structured XML") .... Ops, dla CDATA, jak @txyoji zasugerował spłaszczenie elementów CDATA $xml = simplexml_load_file("myfile.xml",'SimpleXMLElement',LIBXML_‌​NOCDATA);.
Peter Krauss
Wielkie dzięki za niestandardową funkcję! To sprawia, że ​​strojenie jest dość łatwe. Przy okazji, dodano wyedytowaną wersję funkcji, która analizuje XML w sposób JS: każdy wpis ma swój własny obiekt (wpisy nie są przechowywane w jednej tablicy, jeśli mają równe zmienne), więc kolejność jest zachowana.
lucifer63
1
Błąd Fatal error: Uncaught Error: Call to a member function getName() on bool... myślę, że wersja php nie powiodła się :-( .. proszę o pomoc!
KingRider
10

Częstym błędem jest zapomnienie, że json_encode()nie uwzględnia elementów z wartością tekstową i atrybutami. Wybierze jeden z nich, czyli dataloss. Poniższa funkcja rozwiązuje ten problem. Jeśli zdecydujesz się wybrać drogę json_encode/ decode, zaleca się następującą funkcję.

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

w ten sposób <foo bar="3">Lorem</foo>nie skończy się tak, jak {"foo":"Lorem"}w Twoim JSON.

Koder zbawienia
źródło
Nie kompiluje się i nie generuje opisanych wyników, jeśli błędy składniowe są poprawione.
Richard Kiefer,
Co to jest $dom? Skąd to pochodzi?
Jake Wilson
$ dom = new DOMDocument (); to skąd pochodzi
Scott
1
Ostatnia linia kodu: $ json = json_decode (json_encode ($ sxml))); powinno być: $ json = json_decode (json_encode ($ sxml));
Charlie Smith
6

Spróbuj tego użyć

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

Lub

Możesz skorzystać z tej biblioteki: https://github.com/rentpost/xml2array

Ajay Kumar
źródło
3

W tym celu użyłem TypeConvertera Milesa Johnsona . Można go zainstalować za pomocą Composera .

Możesz napisać coś takiego, używając go:

<?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);
Ochrypły
źródło
3

Optymalizacja odpowiedzi Antonio Maxa:

$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
źródło
4
Użyłem tego podejścia, ale JSON jest pusty. XML jest prawidłowy.
ryabenko-pro
2

Jeśli chcesz przekonwertować tylko określoną część XML na JSON, możesz użyć XPath, aby to pobrać i przekonwertować na 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);
?>

Pamiętaj, że jeśli Xpath jest niepoprawny, to zniknie z błędem. Więc jeśli debugujesz to za pomocą wywołań AJAX, zalecamy również rejestrowanie treści odpowiedzi.

ChrisR
źródło
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
źródło
2

Najlepsze rozwiązanie, które działa jak urok

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

Źródło

Alfa
źródło
1

Jest to ulepszenie najpopularniejszego rozwiązania Antonio Maxa, które działa również z XML, który ma przestrzenie nazw (zastępując dwukropek podkreśleniem). Ma również kilka dodatkowych opcji (i <person my-attribute='name'>John</person>poprawnie analizuje ).

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
źródło
2
Nie używa się Regex do analizowania XML, chyba że jest to prosty XML o banalnej strukturze i bardzo przewidywalnych danych. Nie mogę wystarczająco podkreślić, jak złe jest to rozwiązanie. To ŁAMIE DANE. Nie wspominając o tym, że jest niewiarygodnie powolny (parsujesz za pomocą wyrażenia regularnego, a następnie ponownie parsujesz?) I nie obsługuje samozamykających się tagów.
AlexanderMP,
Nie sądzę, żebyś naprawdę przyjrzał się tej funkcji. Nie używa wyrażenia regularnego do właściwego parsowania, a jedynie jako prostą poprawkę do radzenia sobie z przestrzeniami nazw - która działała we wszystkich moich przypadkach xml - i to, że działa, jest najważniejsze, a nie "politycznie poprawne". Możesz go jednak ulepszyć, jeśli chcesz!
TheStoryCoder
2
Fakt, że ci się udało, nie oznacza, że ​​jest słuszny. To taki kod, który generuje błędy, które są niezwykle trudne do zdiagnozowania i generuje exploity. Chodzi mi o to, że nawet powierzchowne spojrzenie na specyfikacje XML w witrynach takich jak w3schools.com/xml/xml_elements.asp pokazuje wiele powodów, dla których to rozwiązanie nie działa. Jak powiedziałem, nie wykrywa samozamykających się tagów, takich jak <element/>, nie adresuje elementów, które zaczynają się od lub zawierają podkreślenia, co jest dozwolone w XML. Nie można wykryć CDATA. I jak powiedziałem, jest WOLNY. Jest to złożoność O (n ^ 2) z powodu wewnętrznego parsowania.
AlexanderMP
1
Chodzi o to, że zajmowanie się przestrzeniami nazw nie było tutaj nawet pytane, a są WŁAŚCIWE sposoby radzenia sobie z przestrzeniami nazw. Przestrzenie nazw istnieją jako pomocna konstrukcja, NIE należy ich analizować w ten sposób i przekształcać w obrzydliwość, która nie będzie przetwarzana przez żaden rozsądny parser. I wszystko, co trzeba było zrobić, to nie stworzyć pretendenta do nagrody „najwolniejszego algorytmu 2016 roku”, ale trochę poszukać i znaleźć niezliczoną ilość rzeczywistych rozwiązań, takich jak ten stackoverflow.com/ pytania / 16412047 /… I nazwać to poprawą? Łał.
AlexanderMP
0

Wszystkie rozwiązania mają tutaj problemy!

... Gdy reprezentacja wymaga doskonałej interpretacji XML (bez problemów z atrybutami) i odtworzenia całego tekstu-znacznika-tekstu-znacznika-tekstu -... i kolejności znaczników. Warto też pamiętać, że obiekt JSON „jest nieuporządkowanym zestawem” (nie powtarzają się klucze, a klucze nie mogą mieć predefiniowanej kolejności) ... Nawet xml2json ZF jest zły (!), Ponieważ nie zachowuje dokładnie struktury XML.

Wszystkie tutaj rozwiązania mają problemy z tym prostym kodem XML,

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

... Rozwiązanie @FTav wydaje się lepsze niż rozwiązanie 3-liniowe, ale ma również mały błąd podczas testowania z tym XML.

Stare rozwiązanie jest najlepsze (dla reprezentacji bez strat)

Rozwiązanie, dziś dobrze znane jako jsonML , jest używane przez projekt Zorba i inne, a po raz pierwszy zostało zaprezentowane w ~ 2006 lub ~ 2007 roku przez (osobno) Stephena McKameya i Johna Snelsona .

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

Produkować

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

Zobacz http://jsonML.org lub github.com/mckamey/jsonml . Reguły produkcji tego JSON są oparte na elemencie JSON-analog,

wprowadź opis obrazu tutaj

Ta składnia jest definicją elementu i powtarzaniem, z
element-list ::= element ',' element-list | element.

Peter Krauss
źródło
2
Bardzo nietypowa struktura xml, w którą wątpię, aby miała rzeczywiste przypadki użycia.
TheStoryCoder
0

Po przeanalizowaniu wszystkich odpowiedzi, wymyśliłem rozwiązanie, które działało dobrze z moimi funkcjami JavaScript w różnych przeglądarkach (w tym na konsolach / narzędziach deweloperskich):

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

?>

Zasadniczo tworzy nowy DOMDocument, ładuje i plik XML do niego i przechodzi przez każdy z węzłów i elementów potomnych, pobierając dane / parametry i eksportując je do JSON bez irytujących znaków „@”.

Link do pliku XML .

Xedret
źródło
0

To rozwiązanie obsługuje przestrzenie nazw, atrybuty i daje spójne wyniki z powtarzającymi się elementami (zawsze w tablicy, nawet jeśli występuje tylko jedno wystąpienie). Zainspirowany 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);
}

Przykład:

php > print(json_encode(xmlToArr('<root a="5"><b>6</b></root>')));
{"root":[{"a":"5","b":["6"]}]}
Klesun
źródło
to faktycznie działa w przypadku wielu przestrzeni nazw, lepiej niż inne rozwiązania, dlaczego dostałem głos
negatywny
0

Okazało się, że odpowiedź FTav jest najbardziej użyteczna, ponieważ jest bardzo konfigurowalna, ale jego funkcja xml2js ma kilka wad. Na przykład, jeśli elementy potomne mają takie same zmienne, wszystkie będą przechowywane w jednym obiekcie, oznacza to, że kolejność elementów nie zostanie zachowana. W niektórych przypadkach naprawdę zależy nam na zachowaniu porządku, dlatego lepiej przechowujemy dane każdego elementu w osobnym obiekcie:

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

Oto jak to działa. Początkowa struktura xml:

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

Wynik JSON:

{
    "some-tag": {
        "some-attribute": "value of some attribute",
        "children": [
            {
                "another-tag": {
                    "content": "With text"
                }
            },
            {
                "surprise": []
            },
            {
                "another-tag": {
                    "content": "The last one"
                }
            }
        ]
    }
}
lucifer63
źródło
-1

Wygląda na to, że $state->namezmienna zawiera tablicę. Możesz użyć

var_dump($state)

wewnątrz, foreachaby to sprawdzić.

W takim przypadku możesz zmienić linię wewnątrz foreachna

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

aby to poprawić.

Michael Fenwick
źródło
wygląda na to, że atrybuty są tablicami, ale nie $ 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
źródło
Jest to małe i uniwersalne rozwiązanie oparte na szeregu danych, które może być json_decode przekształconym w JSON ... szczęście
Octavio Perez Gallegos
2
W jaki sposób to odpowiada na pierwotne pytanie? Twoja odpowiedź wydaje się bardziej skomplikowana niż pierwotne pytanie, a także wydaje się, że nigdzie nie wspomina o JSON.
Dan R
-1

Jeśli jesteś użytkownikiem Ubuntu zainstaluj czytnik XML (mam php 5.6. Jeśli masz inny, znajdź pakiet i zainstaluj)

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
źródło