wake-up-neo.com

PHP XML in JSON konvertieren

Ich versuche, XML in PHP in Json zu konvertieren. Wenn ich eine einfache Konvertierung mit einfachem XML und json_encode mache, wird keines der Attribute in der XML-Show 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 den Status ist {"state":{"0":"Alabama"}} und nicht {"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"
}
}
}
120
Bryan Hadlock

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

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

Json & Array aus XML in 3 Zeilen:

$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
381
Antonio Max

Es tut uns leid, dass Sie auf einen alten Beitrag geantwortet haben, aber dieser Artikel beschreibt einen Ansatz, der relativ kurz, kurz und einfach 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;
    }
}
?>
33
Coreus

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

Ausschlussklausel: Ich bin kein PHP Native, also bitte ertragen Sie sich mit einfachen Fehlern.

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

Verwendungsbeispiel:

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

Beispieleingabe (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 zu beachten sind: Mehrere Tags mit demselben Namen 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, auch wenn er nur ein untergeordnetes Element hat, ein Array, das für jede Instanz des Tages ein Objekt 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 "_" - Child gespeichert.

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

{
    "states" : [{
            "state" : [{
                    "$" : {
                        "id" : "AL"
                    },
                    "name" : [{
                            "_" : "Alabama"
                        }
                    ]
                }, {
                    "$" : {
                        "id" : "AK"
                    },
                    "name" : [{
                            "_" : "Alaska"
                        }
                    ]
                }
            ]
        }
    ]
}
15
FTav

Eine häufige Falle ist zu vergessen, dass json_encode() Elemente mit einem Textwert und -Attribut (en) nicht respektiert. Es wird eine davon ausgewählt, was "dataloss" bedeutet. Die folgende Funktion löst dieses Problem. Wenn Sie sich für den json_encode/decode-Weg entscheiden, 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 wird <foo bar="3">Lorem</foo> nicht als {"foo":"Lorem"} in Ihrem JSON enden.

8

Versuchen Sie dies zu benutzen

$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

6
Ajay Kumar

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

Sie könnten so etwas 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);
3
Husky

Optimierung der Antwort von 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);
3
Marco Leuti

Dies ist eine Verbesserung der von Antonio Max am meisten bewerteten Lösung, die auch mit XML arbeitet, das über Namespaces verfügt (durch Ersetzen des Doppelpunkts durch einen Unterstrich). 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;
}
2
TheStoryCoder

Wenn Sie nur einen bestimmten Teil des XML in JSON konvertieren möchten, können Sie diesen mit XPath abrufen und in JSON 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 bei fehlerhaftem Xpath ein Fehler auftritt. Wenn Sie also über AJAX -Aufrufe debuggen, empfiehlt es sich, auch die Antwortkörper zu protokollieren.

1
ChrisR

Diese Lösung verarbeitet Namespaces, Attribute und erzeugt konsistente Ergebnisse mit sich wiederholenden Elementen (immer im Array, auch wenn es nur ein Vorkommen gibt) . Inspiriert durch ratfactors sxiToArray () .

/**
 * <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"]}]}
0
Artur Klesun

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);
0
Atul Baldaniya

Alle Lösungen hier haben Probleme!

... Wenn die Darstellung eine perfekte XML-Interpretation erfordert (ohne Probleme mit Attributen) und um alle Text-Tag-Text-Tag-Text -... und die Reihenfolge der Tags zu reproduzieren. Denken Sie auch daran, dass JSON-Objekt "eine ungeordnete Menge ist" (Schlüssel nicht wiederholen und die Schlüssel können keine vordefinierte Reihenfolge haben) ... Sogar ZFs xml2json ist falsch (!) weil nicht genau die XML-Struktur erhalten.

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>

Die @FTav-Lösung scheint besser zu sein als die 3-Zeilen-Lösung, hat jedoch auch einen kleinen Fehler, wenn sie mit diesem XML getestet wird.

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

Die heute unter dem Namen jsonML bekannte Lösung wird von Zorba-Projekt und anderen verwendet und wurde erstmals 2006 oder 2007 von (gesondert) Stephen McKamey vorgestellt. _ und 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);

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 dieser JSON basieren auf dem JSON-Analogelement element

enter image description here

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

0
Peter Krauss

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

<?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 Wesentlichen ein neues DOMDocument, lädt eine XML-Datei und durchläuft jeden Knoten und jedes untergeordnete Element, wobei die Daten/Parameter abgerufen und in JSON ohne lästige "@" - Zeichen exportiert werden.

Verknüpfen Sie mit der Datei XML .

0
Xedret

Die Frage sagt es nicht, aber normalerweise bringt PHP JSON auf eine Webseite zurück.

Ich finde es viel einfacher, XML über eine JS-Bibliothek in den Browser/die Seite in JSON zu konvertieren, zum Beispiel:

https://code.google.com/p/x2js/downloads/detail?name=x2js-v1.1.3.Zip
0
Bret Weinraub

Sieht aus, als ob die Variable $state->name 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 in der Variable foreach in ändern 

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

um es zu korrigieren.

0
Michael Fenwick
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;
0
Rashiqul Rony