Get values from Multidimensional nested array in PHP - php

Hi I am trying to get fulltext values from this json file on this Link
I am getting only top of the array how can I get all values from all arrays even the nested ones
$json_output = json_decode($json, true);
var_dump($json_output);
foreach($json_output['results'] as $item) {
echo '<br/>'. $item['fulltext'];
}

Id try looking at spl in PHP, it gives you useful iterator classes including ones specially for complex arrays - http://php.net/manual/en/class.recursivearrayiterator.php

another approach would be to
1) convert your json to xml (json -> php array -> xml) - you can use this recursive function:
function to_xml(SimpleXMLElement $object, array $data)
{
foreach ($data as $key => $value)
{
if (is_array($value))
{
$new_object = $object->addChild($key);
to_xml($new_object, $value);
}
else
{
$object->addChild($key, $value);
}
}
}
$xml = new SimpleXMLElement('<rootTag/>');
to_xml($xml, $my_array);
2) query the xml with XPath to fetch the collection of data you need, for example
$titles = $xml->xpath('//#fulltext');
Utilising XPath you can easily fetch data also by complex constraints, check out the docs

Found a solution
foreach($json_output['results'] AS $result) {
foreach($result['printouts']['Covers topic'] AS $topic) {
echo "<ul><li>".$topic['fulltext']."</li></ul>";
}
echo "<br/>".$result['fulltext'];
}
Thanks for your help guys

Related

Converting multidimensional SimpleXML to associative array

I have a nested multidimensional XML string that I get into SimpleXML. I want to convert it into an associative array. The examples listed on php.net do not work correctly or they do only for flat xmls.
This works better than the example on SimpleXML manual page, but in its current form it discards the attributes.
function xml2array($xmlObject, $out = array())
{
foreach ($xmlObject as $node) {
if ($node->count() > 0) {
$out[$node->getName()][] = xml2array($node);
} else {
$out[$node->getName()] = (string)$node;
}
}
return $out;
}

Speed up recursive foreach using php

I am running this against an associative (non-numerical keys) array that is 80K lines, decoded from a 2.1K json file:
$ret = array();
function recursive(array $array, $tableName, $level=''){
global $ret;
$tableData = array();
foreach($array as $key => $value){
if(!is_array($key)) $k = $key; // keep array keys for tablename
if(is_array($value)){
$key = is_int($key) ? $tableName : $key; //skip empty subarrays
recursive($value, $level=$key);
} else{
$tableData=[$tableName, $k, $value];
}
if (!empty($tableData))
{array_push($ret, $tableData);
}
}
return $ret;
}
$ret =(recursive($array, 'project'));
The json data contains empty sub-arrays which are discarded during the 'is_int($key) recursive loop. This is a typical file size that will be processed and the function is taking over 2 mins to run - which may be as good as it gets - but I wanted to ask if there were any ways to speed this function up by better coding.
thank you,
It seems to be always true: if(!is_array($key)) $k = $key;
You are don't use the $level variable. Why do you need it?
Globals are really bad idea. You probably need to send variables to your function by link instead of value:
function recursive(&$data, &$result, $tableName)
{
//some of your logic here
//...
//if you need a recursion call
recursive($data, $result, $tableName);
}
//function call
$result = [];
recoursive($data, $result, 'project');
//all of your data now in the result variable
Also it may be a good idea to read and process your data by chunks. Iterators or generators can help you with this.

Customize json_decode behaviour

I have a JSON string returned by a REST API which follows:
'{"success":true,"product":{"id":"2","category_id":"2","type":"9","name":".ch","description":"","visible":"1","domain_options":"0","stock":"0","qty":"0","autosetup":"2","subdomain":"","owndomain":"0","tax":"0","upgrades":"","sort_order":"0","client_limit":"0","rel":"Product","paytype":"DomainRegular","m_setup":"0.00","q_setup":"0.00","s_setup":"0.00","a_setup":"0.00","b_setup":"0.00","t_setup":"0.00","p4_setup":"0.00","p5_setup":"0.00","d_setup":"0.00","w_setup":"0.00","h_setup":"0.00","m":"0.00","q":"0.00","s":"0.00","a":"0.00","b":"0.00","t":"0.00","p4":"0.00","p5":"0.00","d":"0.00","w":"0.00","h":"0.00","ptype":"DomainsType","options":"3","module":"13","server":"","tlds":null,"periods":{"1":{"product_id":"2","period":"1","register":"17.00","transfer":"17.00","renew":"17.00"}},"tag_name":".ch","tag_description":"","free_domain":"0","product_id":"2","not_renew":"0","epp":true,"ns":["ns3.dfinet.ch","ns4.dfinet.ch","",""],"nsips":"|||","tld":".ch","nsip":["","","",""],"asciimode":true,"app_id":"1","app_ns1":"","app_ns2":"","app_ns3":"","app_ns4":"","app_ip1":"","app_ip2":"","app_ip3":"","app_ip4":"","emails":{"AfterRegistrarRegistration":"28","AfterRegistrarRenewal":"29","AfterRegistrarTransfer":"30","expiringDomain":"54"}},"config":false,"call":"getProductDetails","server_time":1412061849}'
I am trying to convert this to an object and then serve an XML for a soap webservice, what I was doing up to now was
retrieving the result from the rest API -> convert it to object with json_decode($obj)
serve the soap handle() with the converted object
The problem is that, with the following JSON, there are some properties that are "numeric" but not sequential, so the JSON convert the string to an object as follows:
$o = new stdClass();
$o->1 = 'a string';
The problem is that when soap converts object to XML, the node named <1> is an invalid XML markup.
What can I do to "pre-parse" the JSON and convert all of those fake objects to sequentials arrays?
EDIT: Solution based on dmikam answer
I did something cleaner based on the proposed solution:
function fixVariables($variables)
{
if (!is_array($variables) && !is_object($variables)) {
return $variables;
}
foreach ($variables as $k => &$variable) {
if (is_object($variable)) {
if (is_numeric(key($variable))) {
$values = array();
foreach ($variable as $value) {
$values[] = $value;
}
$variable = $values;
unset($values);
}
$this->fixVariables($variable);
} elseif (is_array($variable)) {
if (is_numeric(key($variable))) {
$variable = array_values($variable);
}
$this->fixVariables($variable);
}
}
return $variables;
}
Well, I think you could walk through the resulting parsed object and convert all items that contains numeric indexes into arrays. The function would be something like this:
function fixJsonObject($obj){
if (is_object($obj)){
foreach(get_object_vars($obj) as $key=>$value){
$obj->$key = fixJsonObject($obj->$key);
if (is_numeric($key)){
return (array)$obj;
}
}
}elseif (is_array($obj)){
foreach($obj as $key=>$value){
$obj[$key] = fixJsonObject($obj[$key]);
}
}
return $obj;
}
$json = json_decode('{your: "json"}');
$json = fixJsonObject($json);
I have tested it a bitand looks like it works.

how to cast an xml object to a associative array?

I am doing some geocoding with the google api and was wondering how do i cast the returned simplexml object? I tried the following but it does no cast the child objects.. ie.. i would like a multi dimensional array.
$url = "http://maps.googleapis.com/maps/api/geocode/xml?address=".$adr."
&sensor=false";
$result = simplexml_load_file($url);
$result = (array) $result;
You could make a JSON request rather than XML; it's recommended; unless your application requires it. Then use:
json_decode( $result, true );
http://us2.php.net/manual/en/function.json-decode.php
I found very useful this function for converting Object to Array recursively:
http://forrst.com/posts/PHP_Recursive_Object_to_Array_good_for_handling-0ka
Adapted from the site above, to use it outside classes:
function object_to_array($obj) {
$arrObj = is_object($obj) ? get_object_vars($obj) : $obj;
foreach ($arrObj as $key => $val) {
$val = (is_array($val) || is_object($val)) ? object_to_array($val) : $val;
$arr[$key] = $val;
}
return $arr;
}
Turn the SimpleXMLElement object into json and decode the json string again into an associative array:
$array = json_decode(json_encode($result), 1);
The simple cast to array does not go more deep in there, that's why the trick via json_encode and json_decode is used.

Multidimensional Arrays Nested to Unlimited Depth

I have a multidimensional array nested to an unknown/unlimited depth.
I'd like to be able to loop through every element.
I don't want to use, foreach(){foreach(){foreach(){}}} as I don't know the depth.
I'm eventually looking for all nested arrays called "xyz". Has anyone got any suggestions?
I'm eventually looking for all nested arrays called "xyz". Has anyone got any suggestions?
Sure. Building on the suggestions to use some iterators, you can do:
$iterator = new RecursiveIteratorIterator(
new RecursiveArrayIterator($array),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($iterator as $key => $item) {
if (is_array($item) && $key === 'xyz') {
echo "Found xyz: ";
var_dump($item);
}
}
The important difference between the other answers and this being that the RecursiveIteratorIterator::SELF_FIRST flag is being employed to make the non-leaf (i.e. parent) items (i.e. arrays) visible when iterating.
You could also make use of a ParentIterator around the array iterator, rather than checking for arrays within the loop, to make the latter a little tidier.
Recursion.
Write a function that walks one array; for each element that is also an array, it calls itself; otherwise, when it finds the target string, it returns.
There is a vast difference between unknown and unlimited. However, you can make use of the SPL Iterators instead of using multiple nested foreach loops.
Example:
$array_obj = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
foreach($array_obj as $key => $value) {
echo $value;
}
Take a look to the RecursiveIteratorIterator interface.
$interface = new RecursiveIteratorIterator( new RecursiveArrayIterator($your_array) );
foreach($interface as $k=>$v) { /* your function*/ }
Using the comments above, I've found the answer:
function findXyz($array){
foreach($array as $foo=>$bar){
if (is_array($bar)){
if ($bar["xyz"]){
echo "<br />The array of xyz has now been found";
print_r($bar['xyz']);
}else{
findXyz($bar);
}
}
}
}
findXyz($myarray);
This loops through all nested arrays and looks for any element who has a sub-array of xyz, as per my original request. array_walk_array and RecursiveIteratorIterator were unable to achieve this.
Have you thought about using array_walk_recursive for this?
Another (slower) approach would be to flatten the array first before performing a search, ie:
$myarray = array('a','b',array(array(array('x'),'y','z')),array(array('p')));
function array_flatten($array,$return)
{
for($x = 0; $x <= count($array); $x++)
{
if(is_array($array[$x]))
{
$return = array_flatten($array[$x],$return);
}
else
{
if($array[$x])
{
$return[] = $array[$x];
}
}
}
return $return;
}
$res = array_flatten($myarray,array());
Or, for a recursive search, see here for an example:
function arrayRecursiveSearch($needle, $haystack, $path=""){
if(!is_array($haystack)){
die("second argument is not array");
}
global $matches;
foreach($haystack as $key=>$value)
{
if(preg_match("/$needle/i", $key)){
$matches[] = array($path . "$key/", "KEY: $key");
}
if(is_array($value)){
$path .= "$key/";
arrayRecursiveSearch($needle, $value, $path);
unset($path);
}else{
if(preg_match("/$needle/i", $value)){
$matches[] = array($path . "$key/", "VALUE: $value");
}
}
}
return $matches;
}
$arr = array("Asia"=>array('rambutan','duku'),
"Australia"=>array('pear','kiwi'),
"Arab"=>array('kurma'));
print_r(arrayRecursiveSearch("ra",$arr));

Categories