PHP将XML转换为JSON

我想在PHP中将XML转换为JSON。 如果我使用简单的xml和json_encode进行简单的转换,则不会显示xml中的任何属性。

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

所以我正在尝试像这样手动parsing它。

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

来自XML的Json&Array 3行:

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

达达!

对于回复旧post感到抱歉,但这篇文章概述了一个相对简短,简洁且易于维护的方法。 我自己testing过,工作得很好。

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处理不同于string的对象。 我将对象转换为一个string,现在它可以工作。

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

我想我晚了一点,但我写了一个小function来完成这个任务。 它还处理属性,文本内容以及具有相同节点名称的多个节点是兄弟节点。

免责声明:我不是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); 

示例input(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" } ] } ] } ] } 

要记住的怪癖:具有相同标记名的几个标记可以是兄弟。 其他解决scheme将最有可能放弃所有,但最后的兄弟姐妹。 为了避免这种情况,即使只有一个子节点,每个节点都是一个数组,它为每个标记名实例保存一个对象。 (请参阅示例中的多个“”元素)

即使是根元素,其中只有一个应该存在于一个有效的XML文档中,也是以一个实例的对象作为数组存储,只是为了具有一致的数据结构。

为了能够区分XML节点内容和XML属性,每个对象属性都存储在“$”和“_”子内容中。

编辑: 我忘了显示您的示例input数据的输出

 { "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()不尊重具有文本值属性的元素。 它会select其中的一个,意思是dataloss。 下面的function解决了这个问题。 如果决定采用json_encode / decode方式,build议使用以下函数。

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

通过这样做,在您的JSON中, <foo bar="3">Lorem</foo>不会最终成为{"foo":"Lorem"}

我已经使用了Miles Johnson的TypeConverter来达到这个目的。 它可以使用Composer进行安装。

你可以使用它来写这样的东西:

 <?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的特定部分转换为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调用来debugging,我build议你也logging响应体。

这是Antonio Max最有利的解决scheme的一个改进,Antonio Max也使用具有名称空间的XML(通过用下划线replace冒号)。 它还有一些额外的选项(并正确parsing<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; } 

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

看起来像$state->namevariables是持有一个数组。 您可以使用

 var_dump($state) 

里面的foreach来testing一下。

如果是这样的话,你可以改变foreach内的行

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

纠正它。

这个问题没有说明,但通常PHP正在返回JSON到一个网页。

我发现通过JS库在浏览器/页面中将XML转换为JSON要容易得多,例如:

 https://code.google.com/p/x2js/downloads/detail?name=x2js-v1.1.3.zip 

所有的解决scheme都有问题!

…当表示需要完美的XML解释(没有属性问题),并重现所有的文本标签文本标签文本…和标签的顺序。 还记得在这里, JSON对象 “是一个无序集”(不重复键和键不能有预定义的顺序)…即使ZF的xml2json是错误的(!),因为不能保存完整的XML结构。

这里所有的解决scheme都有这个简单的XML问题,

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

… @FTAV解决scheme似乎比3-line解决scheme更好,但使用此XML进行testing时也有小错误。

旧的解决scheme是最好的(无损失表示)

这个解决scheme现在被称为jsonML ,被Zorba项目和其他人所使用,最初是在2006年或2007年由Stephen McKamey和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 xx=\'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",{"xx":"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 element-list ::= element ',' element-list | element

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