I am trying to convert xml to json in php. If I do a simple convert using simple xml and json_encode none of the attributes in the xml show.
$xml = simplexml
This is an improvement of the most upvoted solution by Antonio Max, which also works with XML that has namespaces (by replacing the colon with an underscore). It also has some extra options (and does parse <person my-attribute='name'>John</person>
correctly).
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;
}
Try to use this
$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;
Or
You can use this library : https://github.com/rentpost/xml2array
If you would like to only convert a specific part of the XML to JSON, you can use XPath to retrieve this and convert that to 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);
?>
Please note that if you Xpath is incorrect, this will die with an error. So if you're debugging this through AJAX calls I recommend you log the response bodies as well.
This solution handles namespaces, attributes, and produces consistent result with repeating elements (always in array, even if there is only one occurrence). Inspired by ratfactor's 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);
}
Example:
php > print(json_encode(xmlToArr('<root a="5"><b>6</b></root>')));
{"root":[{"a":"5","b":["6"]}]}
Json & Array from XML in 3 lines:
$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
If you are ubuntu user install xml reader (i have php 5.6. if you have other please find package and install)
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);