I am trying to have PHP read an XML file and then convert it to JSON to use in some classes that I wrote. The problem I am having is it will not loop thru all XML nodes.
For some reason it will only return one node and not both. My guess is maybe my JSON object is not formatted correctly. I have been messing with this for about 2 days, ugh! I am new to this so go easy on me ;)
tracker.xml
<?xml version="1.0" encoding="UTF-8"?>
<tracker>
<student>
<id>0425655</id>
<lname>Doe</lname>
<fname>John</fname>
</student>
<student>
<id>0123456</id>
<lname>Smith</lname>
<fname>Jane</fname>
</student>
</tracker>
xml.php
class xml
{
private $path;
public function __construct($path)
{
$this->path = $path;
}
public function xmlParse()
{
$xml = simplexml_load_file($this->path);
return json_encode($xml->children());
}
}
json.php
class json
{
private $xmlArray;
public function __construct($xmlArray)
{
$this->xmlArray = $xmlArray;
}
public function getJSON()
{
$json = json_decode($this->xmlArray);
foreach($json->student as $v)
{
return 'ID: '.$v->id.'Last: '.$v->lname.'First: '.$v->fname;
}
}
}
I know I can pass true as a second parameter to json_decode(), but I wanted to work with objects.
Here's the output for the json_decode() (after passing it through getJSON for formatting):
{
"student": [
{
"id": "0425655",
"lname": "Doe",
"fname": "John"
},
{
"id": "0123456",
"lname": "Smith",
"fname": "Jane"
}
]
}
return immediately, well, returns from the current function. You want echo for debugging, as in
foreach($json->student as $v)
{
echo 'ID: '.$v->id.'Last: '.$v->lname.'First: '.$v->fname;
}
If you want to return the result, either just return the JSON object or parse it into an array or string.
That JSON string looks right to me, problem lies with the return statement - as you're looping through an array, use echo instead.
Regarding your JSON
I reformatted your output. As you can see, there are two nodes under "student". Perhaps you missed the [ and ] characters.
Format your JSON next time to get a better idea of what's going on. :)
Regarding your function
You also might have missed it because your debug output is broken:
foreach($json->student as $v)
{
return 'ID: '.$v->id.'Last: '.$v->lname.'First: '.$v->fname;
}
You return after the first iteration.
Try:
$output = '';
foreach ($json->student as $v) {
$output .= "ID: {$v->id} Last: {$v->lname} First: {$v->fname}\n";
}
return $output;
To be honest, though, I'd expect a function named getJSON() to return, well... JSON. Not some author-written string. Your classes and functions are poorly named overall.
Perhaps your function should look like this:
public function getJSON()
{
$json = json_decode($this->xmlArray);
// some debug output for development
foreach ($json->student as $v) {
echo "ID: {$v->id} Last: {$v->lname} First: {$v->fname}\n";
}
return $json;
}
Related
I'm wondering if someone could help me out with a function I'm writing. Basically I'm trying to search through some JSON-LD data for a specific key. The JSON-LD data has been assigned to an array using json_decode. The array looks like this but could have a different format and structure:
{
"#context":"https://schema.org",
"#graph":[
{
"#type":"Organization",
"#id":"https://www.web.site/#organization",
"name":"Some Name",
"url":"https://www.web.site/",
"sameAs":[
"https://www.facebook.com/website",
"https://www.linkedin.com/company/website",
"https://twitter.com/website"
],
"logo":{
"#type":"ImageObject",
"#id":"https://www.web.site/#logo",
"inLanguage":"en",
"url":"https://web.site/logo.svg",
"width":200,
"height":100,
"caption":"Some Name"
},
"image":{
"#id":"https://www.web.site/#logo"
}
},
{
"#type":"WebSite",
"#id":"https://www.web.site/#website",
"url":"https://www.web.site/",
"name":"Some Name",
"inLanguage":"en",
"description":"Some description here.",
"publisher":{
"#id":"https://www.web.site/#organization"
},
"potentialAction":[
{
"#type":"SearchAction",
"target":"https://www.web.site/?s={search_term_string}",
"query-input":"required name=search_term_string"
}
]
},
{
"#type":"WebPage",
"#id":"https://www.web.site/#webpage",
"url":"https://www.web.site/",
"name":"Some Name",
"isPartOf":{
"#id":"https://www.web.site/#website"
},
"inLanguage":"en",
"about":{
"#id":"https://www.web.site/#organization"
},
"datePublished":"2017-01-01T21:21:21+00:00",
"dateModified":"2017-01-01T21:21:21+00:00",
"description":"Some description here.",
"potentialAction":[
{
"#type":"ReadAction",
"target":[
"https://www.web.site/"
]
}
]
}
]
}
The function I have written to find a key looks like this:
function findArrayKey($array, $find) {
foreach($array as $key => $value) {
if (is_array($value)) {
if((string)$key == $find){
foreach($value as $key => $value) {
$info .= $value;
}
} else {
findArrayKey($value,$find);
}
}
}
echo $info; // prints the info
return $info; // returns nothing
}
echo findArrayKey($myarray,$keyimlookingfor);
The echo findArrayKey line at the bottom just does nothing (I've also tried var_dump and print_r and still get nothing) yet the echo within the function works perfectly.
The output from the echo within the function is:
https://www.facebook.com/websitehttps://www.linkedin.com/company/websitehttps://twitter.com/website
The output from the echo outside it (with the data passed back via return) is blank..
Any help someone could provide would be greatly appreciated, thank you for everything in advance.
I have a foreach loop that is supposed to loop through JSON and return the appropriate ID of each video listed in JSON using the Youtube api.
Here is my code:
class Videos {
private $mVideoUrl;
function setVideoTitle($videoUrl){
$this->mVideoUrl= $videoUrl;
}
function getVideoTitle(){
return $this->mVideoUrl;
}
}
$jsonFile = file_get_contents($url);
$jfo = json_decode($jsonFile);
$items = $jfo->items;
$vidArray = array();
foreach ($items as $item){
if(!empty($item->id->videoId)){
$Videos = new Videos;
$Videos->setVideoUrl($item->id->videoId);
$id = $Videos->getVideoUrl();
array_push($vidArray, $id);
}
echo $vidArray[0];
}
Problem is, the array push is working correctly, but it is only adding the 1st ID in the list only for each loop iteration when i echo it. When I echo the $id variable, it prints all IDs just fine.
Ultimately i want to be able to create an object for each video, storing it's ID and other information.
I feel like this is a simple fix but i can't figure it out for the life of me.
I would appreciate any help!
Also if i am going about this all wrong, advice is appreciated as well!
Thanks!
I've played little bit with your code. I've modified your class. I've renamed plurar Videos to Video (singular).
Then I've added an attribute $id, because name of properties should be simple and represent the data we want to store in them.
Then I've added getter and setter for the $id property.
I don't know the $url, so I've just write simple JSON string instead. I tried to mimic the structure that you're using in your code.
Then I've added () to the end of new Video() to have proper constructor called.
And instead of pushing elements into array, I'm using proper $array[$index] = assignment.
Last thing, I've moved writing out the data out of the foreach-cycle. And I'm using var_export to get proper php code to play with if redirected to another file.
<?php
class Video
{
private $mVideoUrl;
private $id; // added id attribute
/**
* #return mixed
*/
public function getId() // added getter
{
return $this->id;
}
/**
* #param mixed $id
*/
public function setId($id) // added setter
{
$this->id = $id;
}
function setVideoTitle($videoUrl)
{
$this->mVideoUrl = $videoUrl;
}
function getVideoTitle()
{
return $this->mVideoUrl;
}
}
// ignored for now
// $jsonFile = file_get_contents($url);
$jsonFile = '{"items": [
{ "id": { "videoId": 1, "url": "http://www.youtube.com/1" } },
{ "id": { "videoId": 2, "url": "http://www.youtube.com/2" } },
{ "id": { "videoId": 3, "url": "http://www.youtube.com/3" } },
{ "id": { "videoId": 4, "url": "http://www.youtube.com/4" } },
{ "id": { "videoId": 5, "url": "http://www.youtube.com/5" } }
]
}';
$jfo = json_decode($jsonFile);
$items = $jfo->items;
$vidArray = array();
foreach ($items as $item)
{
if (!empty($item->id->videoId))
{
$Video = new Video(); // added brackets
$Video->setId($item->id->videoId); // changed to setId
$Video->setVideoTitle($item->id->url);
$id = $Video->getId();
$vidArray[$id] = $Video;
}
}
// write out all data
var_export($vidArray);
In your code your class Videos contains two functions
setVideoTitle(...),
getVideoTitle()
but in your foreach you have called $videos->getVideoUrl() , $videos->setVideoUrl(...)
what is this ???
I have this problem where an API responds to me with DEPARTURESEGMENT sometimes containing only one object, and sometimes containing an array of objects. Depending on which case it is, I seem to need different logics in my foreach-loop.
Response A:
{
"getdeparturesresult":{
"departuresegment":[{
"departure":{
"location":{
"#id":"7461018",
"#x":"12.523958",
"#y":"57.938402",
"name":"Noltorps centrum"
},
"datetime":"2014-12-04 23:05"
},
"direction":"Alingsås station",
"segmentid":{
"mot":{
"#displaytype":"B",
"#type":"BLT",
"#text":"Buss"
},
"carrier":{
"name":"Västtrafik",
"url":"http://www.vasttrafik.se/",
"id":"279",
"number":"1"
}
}
},
{
"departure":{
"location":{
"#id":"7461018",
"#x":"12.523958",
"#y":"57.938402",
"name":"Noltorps centrum"
},
"datetime":"2014-12-04 23:05"
},
"direction":"Alingsås station",
"segmentid":{
"mot":{
"#displaytype":"B",
"#type":"BLT",
"#text":"Buss"
},
"carrier":{
"name":"Västtrafik",
"url":"http://www.vasttrafik.se/",
"id":"279",
"number":"1"
}
}
}
]
}
}
Works with this loop:
foreach ($apiData->getdeparturesresult->departuresegment as $m) {
While this response B:
{
"getdeparturesresult":{
"departuresegment":{
"departure":{
"location":{
"#id":"7461018",
"#x":"12.523958",
"#y":"57.938402",
"name":"Noltorps centrum"
},
"datetime":"2014-12-04 23:05"
},
"direction":"Alingsås station",
"segmentid":{
"mot":{
"#displaytype":"B",
"#type":"BLT",
"#text":"Buss"
},
"carrier":{
"name":"Västtrafik",
"url":"http://www.vasttrafik.se/",
"id":"279",
"number":"1"
}
}
}
}
}
needs a loop like this (otherwise it throws an error):
foreach ($apiData->getdeparturesresult as $m) {
Is there a way to write the loop failsafe for whether DEPARTURESEGMENT is an array of objects or just one object (the brackets [] is the only difference to the structure of the json right?) or do I have to somehow test and see first whether DEPARTURESEGMENT is an array or not, and dispatch to two different loops depending on the outcome?
You have a few methods that can help you:
is_array
is_object
instanceof // if you receive specific object
gettype
json_decode second parameter, which if is set to true, tries to decode the json as an array
In you situation, you would probably be fine by doing the following:
if (is_object($entry)) {
handleObject($entry);
} elseif (is_array($entry) && count($entry)) {
foreach ($entry as $e) {
handleObject($e);
}
}
I have this little useful function in my standard repertoire:
function iter($x) {
if(is_array($x))
return $x;
if(is_object($x)) {
if($x instanceof \Iterator)
return $x;
if(method_exists($x, 'getIterator'))
return $x->getIterator();
return get_object_vars($x);
}
return array($x);
}
This way you can use any variable with foreach without having to check it beforehand:
foreach(iter($whatever) as $item)
...
How about checking whether it's an array or not with is_array?
I made a simple example of it's usage here - http://codepad.org/WNjbIPZF
Given a JSON parsed object with deep nesting, I would like to extract an (array of) image(s) from a nested structure like this:
object: {
type: "...",
title:"...",
description: {
image:[
src:"logo1.png",
...:...
]
},
somethingelse: {
deeper:[
{imageurl:"logo2.jpg"}
]
}
}
how would I create a function that returns an array of images like this?
$images = getAllImagesFromObject(json_parse($jsonstring));
I do not know beforehand how deep the nesting will be and what the key will be, just any string beginning with http and ending on jpg, png and gif would be useful
I do not have any example since I do not know which method to use and I do not care what the key is so some var dump is also ok.
Perhaps even regex the jsonstring for "http://....[jpg|gif|png]" would be a solution
Something like this should do the trick. I did not test though.
function getAllImagesFromObject($obj) {
$result = array();
foreach ($obj as $prop)
if (is_array($prop) || is_object($prop))
$result = array_merge($result, getAllImagesFromObject($prop));
else if (preg_match('/\.(jpg|jpeg|gif|png|bmp)$/', $prop))
$result[] = $prop;
return $result;
}
i have an xml file:
<?xml version="1.0" encoding="utf-8" ?>
<transaction dsxml_version="1.08">
<action>action1</action>
<action>action2</action>
</transaction>
If i use simplexml i can access the first "action" with die following code
$xml = simplexml_load_string($xml_content);
echo $xml->action; // Write "action1"
echo $xml->action[0]; // Write "action1"
echo $xml->action[1]; // Write "action2"
Now i create an array and a try to access it on the same way. But it doesent work.
We have a huge php skipt which use simple xml which contains a logical error. If i can emulate simple xml i can fix this error on one position
try this:
current($xml->action);
echo array_shift(array_slice($xml->action, 0, 1));
or if you're not worried about damaging the original array, $xml->action you can use the following
echo array_shift($xml->action);
Using array_shift will guarantee you get the first element if it's numbered or associative.
You can create a fake or mock object that simulates the behaviour you are looking for:
$action = new SimpleXMLArrayMock($action_array);
$xml->action = $action;
echo "\nFake:\n";
echo $xml->action, "\n"; // Write "action1"
echo $xml->action[0], "\n"; // Write "action1"
echo $xml->action[1], "\n"; // Write "action2"
/**
* Mock SimpleXML array-like behavior
*/
class SimpleXMLArrayMock extends ArrayObject
{
private $first;
public function __construct(array $array)
{
$this->first = (string) $array[0];
parent::__construct($array);
}
public function __toString()
{
return $this->first;
}
}
Demo
use xpath so you can find the element
This would work:
foreach($myarray as $key => $val)
{
print $val;
//if you don't need the rest of the elements:
break;
}
Added:
You can even make it a function:
function get_first_element($myarray)
{
foreach($myarray as $key => $val)
{
return $val;
}
}