PHP преобразование XML в JSON
Я пытаюсь конвертировать xml в json в php. Если я делаю простое преобразование с помощью простого xml и json_encode ни один из атрибутов в xml-шоу.
$xml = simplexml_load_file("states.xml");
echo json_encode($xml);
поэтому я пытаюсь вручную разобрать его так.
foreach($xml->children() as $state)
{
$states[]= array('state' => $state->name);
}
echo json_encode($states);
и выход для состояния {"state":{"0":"Alabama"}}, а не {"state":"Alabama"}
что я делаю не так?
XML:
<?xml version="1.0" ?>
<states>
<state id="AL">
<name>Alabama</name>
</state>
<state id="AK">
<name>Alaska</name>
</state>
</states>
выход:
[{"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"
}
}
}
16 ответов:
JSON & Array из XML в 3 строках:
$xml = simplexml_load_string($xml_string); $json = json_encode($xml); $array = json_decode($json,TRUE);та-да!
извините за ответ на старый пост, но эта статья описывает подход, который является относительно коротким, кратким и простым в обслуживании. Я проверил это сам и работает довольно хорошо.
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; } } ?>
Я понял. json_encode обрабатывает объекты иначе, чем строк. Я бросил объект в строку, и теперь он работает.
foreach($xml->children() as $state) { $states[]= array('state' => (string)$state->name); } echo json_encode($states);
Я думаю, что я немного опоздала на вечеринку, но я написал небольшую функцию для выполнения этой задачи. Он также заботится об атрибутах, текстовом содержимом и даже если несколько узлов с одинаковым именем узла являются братьями и сестрами.
Dislaimer: Я не уроженец PHP, поэтому, пожалуйста, несите с простыми ошибками.
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); } }пример использования:
$xml = simplexml_load_file("myfile.xml"); echo xml2js($xml);пример ввода (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>пример вывод:
{"family":[{"$":{"name":"Johnson"},"child":[{"$":{"name":"John","age":"5"},"toy":[{"$":{"status":"old"},"_":"Trooper"},{"$":{"status":"old"},"_":"Ultrablock"},{"$":{"status":"new"},"_":"Bike"}]}]}]}довольно напечатано:
{ "family" : [{ "$" : { "name" : "Johnson" }, "child" : [{ "$" : { "name" : "John", "age" : "5" }, "toy" : [{ "$" : { "status" : "old" }, "_" : "Trooper" }, { "$" : { "status" : "old" }, "_" : "Ultrablock" }, { "$" : { "status" : "new" }, "_" : "Bike" } ] } ] } ] }причуды, чтобы иметь в виду: Несколько тегов с одним и тем же tagname могут быть братьями и сестрами. Другие решения, скорее всего, отбросят все, кроме последнего брата. Чтобы избежать этого, каждый отдельный узел, даже если он имеет только одного ребенка, является массивом, который содержит объект для каждого экземпляра tagname. (См. несколько "" элементов в Примере)
даже корневой элемент, из которого только один должен существовать в допустимом XML-документе хранится как массив с объектом экземпляра, просто чтобы иметь согласованную структуру данных.
чтобы иметь возможность различать содержимое узла XML и атрибуты XML, атрибуты каждого объекта хранятся в " $ "и содержимом в дочернем элементе"_".
Edit: я забыл показать вывод для вашего примера входных данных
{ "states" : [{ "state" : [{ "$" : { "id" : "AL" }, "name" : [{ "_" : "Alabama" } ] }, { "$" : { "id" : "AK" }, "name" : [{ "_" : "Alaska" } ] } ] } ] }
попробуйте использовать это
$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;или
вы можете использовать эту библиотеку : https://github.com/rentpost/xml2array
общая ловушка состоит в том, чтобы забыть, что
json_encode()не уважает элементы с textvalue и (ы). Он выберет один из них, то есть dataloss. Функция ниже решает эту проблему. Если кто-то решит пойти наjson_encode/decodeспособ, рекомендуется следующая функция.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 ) );таким образом,
<foo bar="3">Lorem</foo>не будет в конечном итоге, как{"foo":"Lorem"}в JSON.
оптимизация Антонио Макс ответил:
$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);
я использовал Майлза Джонсона TypeConverter для этой цели. Это можно установить с помощью композитор.
вы могли бы написать что-то вроде этого, используя его:
<?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);
это улучшение наиболее востребованного решения Антонио Макса, которое также работает с XML, который имеет пространства имен (заменяя двоеточие подчеркиванием). Он также имеет некоторые дополнительные опции (и делает разбор
<person my-attribute='name'>John</person>правильно).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; }
Если вы хотите преобразовать только определенную часть XML в JSON, вы можете использовать XPath для извлечения этого и преобразования этого в 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); ?>обратите внимание, что если вы Xpath неверно, это умрет с ошибкой. Поэтому, если вы отлаживаете это с помощью AJAX-вызовов, я рекомендую вам также регистрировать тела ответов.
выглядит
$state->nameпеременная содержит массив. Вы можете использоватьvar_dump($state)внутри
foreachчтобы проверить это.если это так, вы можете изменить строку внутри
foreachдо$states[]= array('state' => array_shift($state->name));чтобы исправить это.
вопрос не говорит об этом, но обычно PHP возвращает JSON на веб-страницу.
мне гораздо проще конвертировать XML в JSON в браузере / странице через JS lib, например:
https://code.google.com/p/x2js/downloads/detail?name=x2js-v1.1.3.zip
все решения здесь есть проблемы!
... Когда представление нуждается в идеальной интерпретации XML (без проблем с атрибутами) и воспроизводить весь текст-тег-текст-тег-текст-... и порядок тегов. И хорошо помни вот что объект JSON "неупорядоченный набор" (не повторять ключи и ключи не могут иметь предопределенный порядок)... Даже ZF xml2json - это не так (!) потому что не сохранить точно структуру XML.
все решения здесь есть проблемы с этим простым XML,
<states x-x='1'> <state y="123">Alabama</state> My name is <b>John</b> Doe <state>Alaska</state> </states>... Решение @FTav кажется лучше, чем 3-линейное решение, но также имеет небольшую ошибку при тестировании с этим XML.
старое решение является лучшим (для представления без потерь)
решение, сегодня хорошо известный как jsonML, используется проект Зорба и другие, и был впервые представлен в ~2006 или ~2007 года (отдельно) Стивен McKamey и Джон Снельсон.
// 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);производства
["states",{"x-x":"1"}, "\n\t ", ["state",{"y":"123"},"Alabama"], "\n\t\tMy name is ", ["b","John"], " Doe\n\t ", ["state","Alaska"], "\n\t" ]см.http://jsonML.org или github.com/mckamey/jsonml. правила производства этого JSON основаны на элемент JSON-аналоговый,
этот синтаксис является элемент определение и повторение, с
element-list ::= element ',' element-list | element.
$xml = simplexml_load_string($xml_string); $json = json_encode($xml); $array = json_decode($json,TRUE);просто добавьте эти три строки, вы получите правильный вывод: -)
изучив немного все ответы, я придумал решение, которое отлично работало с моими функциями JavaScript в браузерах (включая консоли / инструменты разработки):
<?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' ) ); */ ?>он в основном создает новый DOMDocument, загружает в него XML-файл и проходит через каждый из узлов и дочерних элементов, получая данные / параметры и экспортируя их в JSON без раздражающих знаков"@".
ссылка XML.
$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); } } }

Comments