我试图在php中将xml转换为json。如果我使用简单的xml和json_encode进行简单的转换,那么xml show中没有任何属性。
$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"
}
}
}
答案 0 :(得分:396)
$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
答案 1 :(得分:33)
很抱歉回答旧帖,但本文概述了一种相对简短,简洁且易于维护的方法。我亲自测试过,效果很好。
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;
}
}
?>
答案 2 :(得分:30)
我明白了。 json_encode以不同于字符串的方式处理对象。我将对象转换为字符串,现在可以正常工作。
foreach($xml->children() as $state)
{
$states[]= array('state' => (string)$state->name);
}
echo json_encode($states);
答案 3 :(得分:15)
我想我参加派对有点晚了,但我写了一个小功能来完成这项任务。它还会处理属性,文本内容,即使具有相同节点名的多个节点都是兄弟节点。
<强> 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"
}
]
}
]
}
]
}
要记住的怪癖: 具有相同标记名的几个标签可以是兄弟姐妹。除了最后一个兄弟之外,其他解决方案很可能会下降。为了避免这种情况,即使它只有一个子节点,每个节点都是一个数组,它为每个标记名实例保存一个对象。 (参见示例中的多个“”元素)
即使是根元素,其中只有一个应该存在于有效的XML文档中,它作为数组存储在实例的对象中,只是为了拥有一致的数据结构。
为了能够区分XML节点内容和XML属性,每个对象属性都存储在“$”中,而内容存储在“_”子节点中。
修改强> 我忘了显示示例输入数据的输出
{
"states" : [{
"state" : [{
"$" : {
"id" : "AL"
},
"name" : [{
"_" : "Alabama"
}
]
}, {
"$" : {
"id" : "AK"
},
"name" : [{
"_" : "Alaska"
}
]
}
]
}
]
}
答案 4 :(得分:8)
一个常见的陷阱是忘记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>
不会以JSON中的{"foo":"Lorem"}
结尾。
答案 5 :(得分:6)
尝试使用此
$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;
或
答案 6 :(得分:3)
我为此目的使用了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);
答案 7 :(得分:3)
优化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);
答案 8 :(得分:2)
这是对Antonio Max最受欢迎的解决方案的改进,它也适用于具有命名空间的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;
}
答案 9 :(得分:1)
如果您只想将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调用进行调试,我建议您也记录响应主体。
答案 10 :(得分:1)
let token = UserDefaults.standard.string(forKey: "token") ?? ""
if !token.isEmpty
{
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window = UIWindow(frame: UIScreen.main.bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let yourVC = mainStoryboard.instantiateViewController(withIdentifier:
"initController") as! HomeController
appDelegate.window?.rootViewController = yourVC
appDelegate.window?.makeKeyAndVisible()
super.viewDidLoad()
}
答案 11 :(得分:0)
问题并没有说明,但通常PHP会将JSON返回到网页。
我发现通过JS lib在浏览器/页面中将XML转换为JSON要容易得多,例如:
https://code.google.com/p/x2js/downloads/detail?name=x2js-v1.1.3.zip
答案 12 :(得分:0)
...当表示需要完美的XML解释(没有属性问题)并重现所有text-tag-text-tag-text -...和标签的顺序。同样好记得JSON object&#34;是一个无序的集合&#34; (不重复键,键不能有预定义的顺序)...甚至ZF's 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 ,由Zorba project和其他人使用,并且首次在〜2006或〜2007年由(单独){{3}提出}和Stephen 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"
]
请参阅John Snelson或http://jsonML.org。此JSON的生产规则基于元素 JSON-analog,
此语法是元素定义和重复,其中包含element-list ::= element ',' element-list | element
。
答案 13 :(得分:0)
看起来$state->name
变量持有一个数组。你可以使用
var_dump($state)
在foreach
内进行测试。
如果是这种情况,您可以将foreach
内的行更改为
$states[]= array('state' => array_shift($state->name));
纠正它。
答案 14 :(得分:0)
在研究了所有答案之后,我想出了一个解决方案,该解决方案可以很好地与跨浏览器(包括控制台/开发工具)的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文件。
答案 15 :(得分:0)
如果您是ubuntu用户,请安装xml阅读器(我安装了php 5.6。如果您有其他安装,请找到软件包并安装)
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);
答案 16 :(得分:0)
发现FTav的答案非常有用,因为它非常可定制,但是他的 xml2js 函数存在一些缺陷。例如,如果子元素具有相同的标记名,则它们全部将存储在单个对象中,这意味着将不保留元素的顺序。在某些情况下,我们确实希望保留顺序,因此我们最好将每个元素的数据存储在单独的对象中:
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;
}
这是它的工作方式。初始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>
结果JSON:
{
"some-tag": {
"some-attribute": "value of some attribute",
"children": [
{
"another-tag": {
"content": "With text"
}
},
{
"surprise": []
},
{
"another-tag": {
"content": "The last one"
}
}
]
}
}
答案 17 :(得分:0)
如果XML是Soap文件,则可以使用此文件:
$xmlStr = preg_replace("/(<\/?)(\w+):([^>]*>)/", "$1$2$3", $xmlStr);
$xml = new SimpleXMLElement($xmlStr);
return json_encode($xml);
答案 18 :(得分:0)
$content = str_replace(array("\n", "\r", "\t"), '', $response);
$content = trim(str_replace('"', "'", $content));
$xml = simplexml_load_string($content);
$json = json_encode($xml);
return json_decode($json,TRUE);
这对我有用
答案 19 :(得分:0)
接受(安东尼奥的)回答,来自这样的来源:
<MyData>
<Level1 myRel="parent" myName="AAA">
<Level2 myRel="child1" myName="BBB">
<Level2 myRel="child2" myName="CCC">
...
你会得到这样的数组:
'Level1' =>
[
0 =>
[
'@attributes' =>
[
'myRel' => 'parent'
'myName' => 'AAA'
],
'Level2' =>
[
0 =>
[
'@attributes' =>
[
'myRel' => 'child_1'
'myName' => 'BBB'
],
因此,如果您想拥有键配对数组(而不是 0
数字),请使用您选择的键,即 myName
:
'Level1' =>
[
'AAA' =>
[
'@attributes' =>
[
'myRel' => 'parent'
'myName' => 'AAA'
],
'Level2' =>
[
'BBB' =>
[
'@attributes' =>
[
'myRel' => 'child_1'
'myName' => 'BBB'
],
然后使用xmlToArrayByKey($xmlContent, 'myName')
。代码在这里:
public function xmlToArrayByKey($content, $keyName)
{
try
{
$xml = simplexml_load_string($content, "SimpleXMLElement", LIBXML_NOCDATA );
$array= json_decode( json_encode($xml), TRUE);
return $this->xmlSetChild($array, $keyName);
} catch (Exception $ex) {
return ['xmlerror'=>$ex];
}
}
public function xmlSetChild($array, $keyName, $step=0)
{
$new_array= [];
foreach ($array as $key_1=>$value_1)
{
if (is_array($value_1) && isset($value_1[0]))
{
foreach ($value_1 as $idx=>$value_2)
{
$keyValue = $value_2['@attributes'][$keyName];
$new_array[$key_1][$keyValue] = $this->xmlSetChild($value_2, $keyName, $step+1);
}
}
else{
$new_array[$key_1]=$value_1;
}
}
return $new_array;
}
答案 20 :(得分:-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);
}
}
}
答案 21 :(得分:-1)
$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
只需添加这三行就可以获得正确的输出: - )
答案 22 :(得分:-1)
此解决方案处理名称空间,属性,并通过重复元素(即使只有一次出现,也始终在数组中)产生一致的结果。 受ratfactor's sxiToArray()的启发。
tf.cond
示例:
/**
* <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);
}
答案 23 :(得分:-1)