PHP konvertiert XML in JSON

157

Ich versuche, XML in PHP in JSON zu konvertieren. Wenn ich eine einfache Konvertierung mit einfacher XML und json_encode durchführe, wird keines der Attribute in der XML angezeigt.

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

Also versuche ich es manuell so zu analysieren.

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

und die Ausgabe für Zustand ist {"state":{"0":"Alabama"}}eher als{"state":"Alabama"}

Was mache ich falsch?

XML:

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

Ausgabe:

[{"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
quelle
Bitte fügen Sie einen Ausschnitt aus dem XML und der endgültigen Array-Struktur hinzu, die Sie nach dem Parsen haben. (A var_dumpfunktioniert gut.)
nikc.org
Input, Output und var_dump hinzugefügt
Bryan Hadlock
Einige Anwendungen benötigen eine "perfec XML-zu-JSON-Zuordnung" , dh jsonML , siehe Lösung hier .
Peter Krauss

Antworten:

472

Json & Array aus XML in 3 Zeilen:

$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
Antonio Max
quelle
58
Diese Lösung ist nicht fehlerfrei. XML-Attribute werden vollständig verworfen. So <person my-attribute='name'>John</person>wird interpretiert als <person>John</person>.
Jake Wilson
13
$ xml = simplexml_load_string ($ xml_string, 'SimpleXMLElement', LIBXML_NOCDATA); um cdata-Elemente zu reduzieren.
Txyoji
28
@JakeWilson Vielleicht sind die 2 Jahre vergangen und verschiedene Versionskorrekturen, aber unter PHP 5.6.30 erzeugt diese Methode ALLE Daten. Attribute werden im Array unter dem @attributesSchlüssel gespeichert , sodass es absolut fehlerfrei und wunderschön funktioniert. 3 kurze Codezeilen lösen mein Problem wunderbar.
AlexanderMP
1
Dies funktioniert nicht, wenn Sie mehrere Namespaces haben. Sie können nur einen auswählen, der in den $ json_string übergeht: '(
jirislav
1
Beachten Sie, dass bei dieser Lösung bei mehreren Knoten mit demselben Namen ein Knoten dazu führt, dass ein Schlüssel nur auf ein Element zeigt, bei mehreren Knoten jedoch der Schlüssel auf ein Array von Elementen zeigt: <list><item><a>123</a><a>456</a></item><item><a>123</a></item></list>-> {"item":[{"a":["123","456"]},{"a":"123"}]}. Eine Lösung , bei php.net durch ratfactor löst dieses Problem , indem sie immer speichernde Elemente in einem Array.
Klesun
37

Es tut uns leid, dass Sie einen alten Beitrag beantwortet haben, aber dieser Artikel beschreibt einen Ansatz, der relativ kurz, prägnant und leicht zu pflegen ist. Ich habe es selbst getestet und funktioniert ziemlich gut.

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
quelle
4
Dies funktioniert nicht, wenn Sie mehrere Instanzen desselben Tags in Ihrem XML haben. Json_encode serialisiert am Ende nur die letzte Instanz des Tags.
Am
34

Ich habe es herausgefunden. json_encode behandelt Objekte anders als Zeichenfolgen. Ich habe das Objekt in eine Zeichenfolge umgewandelt und es funktioniert jetzt.

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

Ich glaube, ich bin etwas spät dran, aber ich habe eine kleine Funktion geschrieben, um diese Aufgabe zu erfüllen. Es kümmert sich auch um Attribute, Textinhalte und selbst wenn mehrere Knoten mit demselben Knotennamen Geschwister sind.

Haftungsausschluss: Ich bin kein PHP-Muttersprachler. Bitte tragen Sie einfache Fehler.

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

Anwendungsbeispiel:

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

Beispiel Eingabe (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>

Beispielausgabe:

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

Ziemlich gedruckt:

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

Macken, die Sie beachten sollten: Mehrere Tags mit demselben Tagnamen können Geschwister sein. Andere Lösungen werden höchstwahrscheinlich alle außer dem letzten Geschwister fallen lassen. Um dies zu vermeiden, ist jeder einzelne Knoten, selbst wenn er nur ein untergeordnetes Element hat, ein Array, das ein Objekt für jede Instanz des Tagnamens enthält. (Siehe mehrere "" Elemente im Beispiel)

Sogar das Stammelement, von dem nur eines in einem gültigen XML-Dokument vorhanden sein sollte, wird als Array mit einem Objekt der Instanz gespeichert, um eine konsistente Datenstruktur zu erhalten.

Um zwischen XML-Knoteninhalt und XML-Attributen unterscheiden zu können, werden alle Objektattribute im "$" und der Inhalt im untergeordneten Element "_" gespeichert.

Bearbeiten: Ich habe vergessen, die Ausgabe für Ihre Beispiel-Eingabedaten anzuzeigen

{
    "states" : [{
            "state" : [{
                    "$" : {
                        "id" : "AL"
                    },
                    "name" : [{
                            "_" : "Alabama"
                        }
                    ]
                }, {
                    "$" : {
                        "id" : "AK"
                    },
                    "name" : [{
                            "_" : "Alaska"
                        }
                    ]
                }
            ]
        }
    ]
}
FTav
quelle
Kann es große XML-Daten analysieren?
Volatil3
2
Diese Lösung ist besser, da XML-Attribute nicht verworfen werden. Weitere Informationen dazu, warum diese komplexe Struktur besser ist als vereinfachte, finden Sie unter xml.com/lpt/a/1658 (siehe " Halbstrukturiertes XML") .... Ops für CDATA, da @txyoji vorgeschlagen hat, CDATA-Elemente zu reduzieren $xml = simplexml_load_file("myfile.xml",'SimpleXMLElement',LIBXML_‌​NOCDATA);.
Peter Krauss
Vielen Dank für eine benutzerdefinierte Funktion! Es macht das Stimmen ziemlich einfach. Übrigens wurde eine bearbeitete Version Ihrer Funktion hinzugefügt, die XML auf JS-Weise analysiert: Jeder Eintrag hat ein eigenes Objekt (Einträge werden nicht in einem einzigen Array gespeichert, wenn sie gleiche Tagnamen haben), sodass die Reihenfolge erhalten bleibt.
Lucifer63
1
Fehler Fatal error: Uncaught Error: Call to a member function getName() on bool.. ich denke, eine Version PHP ist fehlgeschlagen :-( .. bitte helfen!
KingRider
10

Eine häufige Gefahr besteht darin, zu vergessen, dass json_encode()Elemente mit einem Textwert und Attributen nicht berücksichtigt werden. Es wird eine davon auswählen, was Datenverlust bedeutet. Die folgende Funktion löst dieses Problem. Wenn man sich für den json_encode/ decodeWeg entscheidet, wird die folgende Funktion empfohlen.

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

auf diese Weise <foo bar="3">Lorem</foo>wird nicht wie {"foo":"Lorem"}in Ihrem JSON enden .

Kodierer der Erlösung
quelle
Kompiliert nicht und erzeugt nicht die beschriebene Ausgabe, wenn Syntaxfehler korrigiert werden.
Richard Kiefer
Was ist $dom? Woher kommt das?
Jake Wilson
$ dom = new DOMDocument (); ist, woher es kommt
Scott
1
Letzte Codezeile: $ json = json_decode (json_encode ($ sxml))); sollte sein: $ json = json_decode (json_encode ($ sxml));
Charlie Smith
6

Versuchen Sie dies zu verwenden

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

Oder

Sie können diese Bibliothek verwenden: https://github.com/rentpost/xml2array

Ajay Kumar
quelle
3

Ich habe Miles Johnsons TypeConverter für diesen Zweck verwendet. Es kann mit Composer installiert werden .

Sie könnten so etwas damit schreiben:

<?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);
Heiser
quelle
3

Antonio Max Antwort optimieren:

$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
quelle
4
Ich habe diesen Ansatz verwendet, aber JSON ist leer. XML ist gültig.
Ryabenko-Pro
2

Wenn Sie nur einen bestimmten Teil des XML in JSON konvertieren möchten, können Sie XPath verwenden, um dies abzurufen und in JSON zu konvertieren.

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

Bitte beachten Sie, dass wenn Ihr Xpath falsch ist, dies mit einem Fehler stirbt. Wenn Sie dies über AJAX-Aufrufe debuggen, empfehle ich Ihnen, auch die Antwortkörper zu protokollieren.

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

Beste Lösung, die wie ein Zauber funktioniert

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

Quelle

Alpha
quelle
1

Dies ist eine Verbesserung der am besten bewerteten Lösung von Antonio Max, die auch mit XML mit Namespaces funktioniert (indem der Doppelpunkt durch einen Unterstrich ersetzt wird). Es hat auch einige zusätzliche Optionen (und analysiert <person my-attribute='name'>John</person>korrekt).

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
quelle
2
Regex wird nicht zum Parsen von XML verwendet, es sei denn, es handelt sich um ein einfaches XML mit einer trivialen Struktur und sehr vorhersehbaren Daten. Ich kann gar nicht genug betonen, wie schlecht diese Lösung ist. Dies bricht Daten. Ganz zu schweigen davon, dass es unglaublich langsam ist (Sie analysieren mit Regex und dann erneut?) Und keine selbstschließenden Tags verarbeitet.
AlexanderMP
Ich glaube nicht, dass Sie sich die Funktion wirklich angesehen haben. Es verwendet keinen regulären Ausdruck, um das eigentliche Parsen durchzuführen, sondern nur als einfache Lösung für den Umgang mit Namespaces - die für alle meine XML-Fälle funktioniert haben - und dass es funktioniert, ist das Wichtigste, anstatt "politisch korrekt" zu sein. Sie können es aber gerne verbessern, wenn Sie möchten!
TheStoryCoder
2
Die Tatsache, dass es für Sie funktioniert hat, bedeutet nicht, dass es richtig ist. Es ist Code wie dieser, der Fehler generiert, die immens schwer zu diagnostizieren sind, und Exploits generiert. Ich meine, selbst oberflächliche XML-Spezifikationen auf Websites wie dieser w3schools.com/xml/xml_elements.asp zeigen viele Gründe, warum diese Lösung nicht funktionieren würde. Wie gesagt, es erkennt keine selbstschließenden Tags wie <element/>, adressiert keine Elemente, die mit beginnen oder Unterstriche enthalten, was in XML zulässig ist. CDATA kann nicht erkannt werden. Und wie gesagt, es ist langsam. Es ist eine O (n ^ 2) -Komplexität aufgrund innerer Analyse.
AlexanderMP
1
Die Sache ist, dass der Umgang mit Namespaces hier nicht einmal gefragt wurde, und es gibt RICHTIGE Möglichkeiten, mit Namespaces umzugehen. Namespaces sind eine hilfreiche Konstruktion, die NICHT so analysiert und in einen Gräuel verwandelt werden darf, der von keinem vernünftigen Parser verarbeitet wird. Und alles, was Sie dafür tun müssen, ist nicht, den Anwärter auf den Preis des "langsamsten Algorithmus von 2016" zu schaffen, sondern ein bisschen zu suchen, um eine Vielzahl von tatsächlichen Lösungen zu finden, wie diese eine stackoverflow.com/ Fragen / 16412047 /… Und um dies eine Verbesserung zu nennen? Beeindruckend.
AlexanderMP
0

Alle Lösungen hier haben Probleme!

... wenn die Darstellung eine perfekte XML-Interpretation benötigt (ohne Probleme mit Attributen) und um alle Text-Tag-Text-Tag-Text -... und die Reihenfolge der Tags zu reproduzieren. Denken Sie auch daran, dass das JSON-Objekt "eine ungeordnete Menge" ist (keine Wiederholungsschlüssel und die Schlüssel können keine vordefinierte Reihenfolge haben) ... Auch ZFs xml2json ist falsch (!), Da die XML-Struktur nicht genau beibehalten wird.

Alle Lösungen hier haben Probleme mit diesem einfachen XML,

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

... @FTav-Lösung scheint besser als 3-Zeilen-Lösung, hat aber auch kleine Fehler, wenn mit diesem XML getestet.

Alte Lösung ist die beste (für verlustfreie Darstellung)

Die heute als jsonML bekannte Lösung wird vom Zorba-Projekt und anderen verwendet und wurde erstmals in den Jahren ~ 2006 oder ~ 2007 von (separat) Stephen McKamey und John Snelson vorgestellt .

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

Produzieren

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

Siehe http://jsonML.org oder github.com/mckamey/jsonml . Die Produktionsregeln dieses JSON basieren auf dem Element JSON-analog,

Geben Sie hier die Bildbeschreibung ein

Diese Syntax ist eine Elementdefinition und Wiederholung mit
element-list ::= element ',' element-list | element.

Peter Krauss
quelle
2
Sehr ungewöhnliche XML-Struktur, von der ich bezweifle, dass sie reale Anwendungsfälle haben würde.
TheStoryCoder
0

Nachdem ich alle Antworten ein wenig recherchiert hatte, fand ich eine Lösung, die mit meinen JavaScript-Funktionen in allen Browsern (einschließlich Konsolen / Entwicklertools) einwandfrei funktioniert:

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

?>

Es erstellt im Grunde ein neues DOMDocument, lädt eine XML-Datei und durchläuft jeden der Knoten und untergeordneten Knoten, um die Daten / Parameter abzurufen und ohne die lästigen "@" - Zeichen in JSON zu exportieren.

Link zur XML- Datei.

Xedret
quelle
0

Diese Lösung verarbeitet Namespaces, Attribute und erzeugt konsistente Ergebnisse mit sich wiederholenden Elementen (immer im Array, auch wenn nur ein Vorkommen vorliegt). Inspiriert von sxiToArray () von 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);
}

Beispiel:

php > print(json_encode(xmlToArr('<root a="5"><b>6</b></root>')));
{"root":[{"a":"5","b":["6"]}]}
Klesun
quelle
Dies funktioniert tatsächlich für Fälle mit mehreren Namespaces, besser als andere Lösungen. Warum wurde eine Abstimmung
abgelehnt
0

Die Antwort von FTav war am nützlichsten, da sie sehr anpassbar ist, aber seine xml2js- Funktion weist einige Mängel auf. Wenn untergeordnete Elemente beispielsweise gleiche Tagnamen haben, werden sie alle in einem einzelnen Objekt gespeichert. Dies bedeutet, dass die Reihenfolge der Elemente nicht beibehalten wird. In einigen Fällen möchten wir die Reihenfolge wirklich beibehalten, daher speichern wir die Daten jedes Elements besser in einem separaten Objekt:

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

So funktioniert es. Anfängliche XML-Struktur:

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

Ergebnis JSON:

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

Es sieht so aus, als ob die $state->nameVariable ein Array enthält. Sie können verwenden

var_dump($state)

in der foreach, um das zu testen.

In diesem Fall können Sie die Zeile innerhalb von foreachto ändern

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

um es zu korrigieren.

Michael Fenwick
quelle
Es sieht so aus, als wären die Attribute Arrays, aber nicht $ 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
quelle
Es ist eine kleine und universelle Lösung, die auf einem Array von Daten basiert und ein JSON-transformierter json_decode sein kann ... Glück
Octavio Perez Gallegos
2
Inwiefern beantwortet dies die ursprüngliche Frage? Ihre Antwort scheint komplizierter als die ursprüngliche Frage zu sein und JSON auch nirgendwo zu erwähnen.
Dan R
-1

Wenn Sie Ubuntu-Benutzer sind, installieren Sie XML-Reader (ich habe PHP 5.6. Wenn Sie andere haben, finden Sie bitte Paket und installieren)

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
quelle