I'm using Laravel to parse an XML file and store it into the DB. Now, it's probably some sort of a stupid mistake I can't put my finger on, but I would really appreciate if someone could check the code and the weird results I'm getting.
The XML has a deep and complex structure, here's a little piece from that's bugging me:
I'm dumping the $nizXMLsp in the end to see what's inside the array of objects:
public function upload(){
$dom = new DomDocument();
$nizBaza = DB::table('offers')->orderBy('id', 'DESC')->first();
$nizXML = array();
$objekat = new stdClass();
$dom->load("storage/X_Lista.xml");
$domXpath = new DomXPath($dom);
$upit = $domXpath->query('//offer');
foreach($upit as $of){
$objekat->Time = $of->getAttribute('Time');
$objekat->Date = $of->getAttribute('Date');
$objekat->betRound = $of->getAttribute('betRound');
$objekat->timestamp = $of->getAttribute('timestamp');
array_push($nizXML, $objekat);
}
if(is_null($nizBaza) or $nizBaza->id != $nizXML[0]->betRound) {
$kolo = new Offer();
$kolo->id = $objekat->betRound;
$kolo->ts = $objekat->Date . " " . $objekat->Time;
$kolo->posix = $objekat->timestamp;
$kolo->save();
//
$nizBaza = DB::table('sportovi')->get();
$nizXMLsp = array(); $objekat_sp = new stdClass();
foreach($dom->getElementsByTagName('sport') as $k=>$v){
$objekat_sp->id = $v->getAttribute('id');
$objekat_sp->name = $v->getAttribute('name');
$objekat_sp->betRound = $v->parentNode->getAttribute('betRound');
$nizXMLsp[$k] = $objekat_sp;
}
}
elseif($nizBaza->id == $nizXML[0]->betRound){
echo 'break1';
exit;
}
else {
echo 'break2';
exit;
}
return var_dump($nizXMLsp);
}
Now, what I see in the end is this:
instead of 4 objects with different sets of data, I get 4 objects with same set of data (all of the data comes from the last node). What could it be?
Possibly a very simple adjustment. Just reset $objekat_sp inside the loop:
foreach($dom->getElementsByTagName('sport') as $k=>$v){
$objekat_sp = "";
$objekat_sp->id = $v->getAttribute('id');
$objekat_sp->name = $v->getAttribute('name');
$objekat_sp->betRound = $v->parentNode->getAttribute('betRound');
$nizXMLsp[$k] = $objekat_sp;
}
Move
$objekat = new stdClass();
and
$objekat_sp = new stdClass();
inside their respective foreach loops.
Right now you're pushing the same object (after modifying its properties) into the array multiple times.
Related
I'm tring to get all content from this xml: https://api.eveonline.com/eve/SkillTree.xml.aspx
To save it on a MySQL DB.
But there are some data missing...
Could any1 that understand PHP, Array() and XML help me, please?
This is my code to get the content:
<?php
$filename = 'https://api.eveonline.com/eve/SkillTree.xml.aspx';
$xmlbalance = simplexml_load_file($filename);
$skills = array();
for ($x=0;$x<sizeOf($xmlbalance->result->rowset->row);$x++) {
$groupName = $xmlbalance->result->rowset->row[$x]->attributes()->groupName;
$groupID = $xmlbalance->result->rowset->row[$x]->attributes()->groupID;
for ($y=0;$y<sizeOf($xmlbalance->result->rowset->row[$x]->rowset->row);$y++) {
$skills[$x]["skillID"] = "".$xmlbalance->result->rowset->row[$x]->rowset->row[$y]->attributes()->typeID;
$skills[$x]["skillName"] = "".$xmlbalance->result->rowset->row[$x]->rowset->row[$y]->attributes()->typeName;
$skills[$x]["skillDesc"] = "".$xmlbalance->result->rowset->row[$x]->rowset->row[$y]->description;
$skills[$x]["skillRank"] = "".$xmlbalance->result->rowset->row[$x]->rowset->row[$y]->rank;
$skills[$x]["skillPrimaryAtr"] = "".$xmlbalance->result->rowset->row[$x]->rowset->row[$y]->requiredAttributes->primaryAttribute;
$skills[$x]["skillSecondAtr"] = "".$xmlbalance->result->rowset->row[$x]->rowset->row[$y]->requiredAttributes->secondaryAttribute;
$o = 0;
for ($z=0;$z<sizeOf($xmlbalance->result->rowset->row[$x]->rowset->row[$y]->rowset->row);$z++) {
if ($xmlbalance->result->rowset->row[$x]->rowset->row[$y]->rowset->attributes()->name == "requiredSkills") {
$skills[$x]["requiredSkills"]["".$xmlbalance->result->rowset->row[$x]->rowset->row[$y]->rowset->row[$z]->attributes()->typeID] = "".$xmlbalance->result->rowset->row[$x]->rowset->row[$y]->rowset->row[$z]->attributes()->skillLevel;
$o++;
}
}
}
}
echo '<pre>'; print_r($skills); echo '</pre>';
?>
If you go to the original XML (link), at line 452, you will see:
<row groupName="Spaceship Command" groupID="257">
And that isn't show in my array (link)...
That is one thing that i found that is missing...
I think that probally have more content that is missing too..
Why? How to fix it, please?
Thank you!!!
You will only get a total of sizeof($xmlbalance->result->rowset->row) records. Because, in your 2nd for loop, you are basically storing your result in the same array element that is $skills[$x].
Try this (I also higly encourage you to be as lazy as you can when you write code - by lazy I mean, avoid repeating / rewriting the same code over and over if possible) :
$filename = 'https://api.eveonline.com/eve/SkillTree.xml.aspx';
$xmlbalance = simplexml_load_file($filename);
$skills = array();
foreach ($xmlbalance->result->rowset->row as $row)
{
$groupName = $row->attributes()->groupName;
$groupID = $row->attributes()->groupID;
foreach ($row->rowset->row as $subRow)
{
$skill['skillID'] = (string) $subRow->attributes()->typeID;
$skill['skillName'] = (string) $subRow->attributes()->typeName;
$skill['skillDesc'] = (string) $subRow->description;
$skill['skillRank'] = (string) $subRow->rank;
$skill['skillPrimaryAtr'] = (string) $subRow->requiredAttributes->primaryAttribute;
$skill['skillSecondAtr'] = (string) $subRow->requiredAttributes->secondaryAttribute;
foreach ($subRow->rowset as $subSubRowset)
{
if ($subSubRowset->attributes()->name == 'requiredSkills')
{
foreach ($subSubRowset->row as $requiredSkill)
{
$skill['requiredSkills'][(string) $requiredSkill->attributes()->typeID] = (string) $requiredSkill['skillLevel'];
}
}
}
$skills[] = $skill;
}
}
print_r($skills);
I'm trying to build a page which queries my database and then formats output so another webservice/page can access the data.
Ideally I wanted to explore having the data in JSON format, but that is not working. The other problem I have which is more major than the JSON not working is, if I have 3 records in $reportsResult, only the last one is displayed.
Anyone with some help please. Oh do I also need to print_r for the external webpage to retrieve the data or is there a better way?
class Pupil {
public $FirstName = "";
public $LastName = "";
}
foreach($reportsResult->getRecords() as $reportRecord) {
$Pupil = new Pupil();
$Pupil->FirstName = $reportRecord->getField('FName');
$Pupil->LastName = $reportRecord->getField('SName');
}
json_encode($Pupil);
OK managed to figure out how how to get all records from the loop, but its still not displaying in json format when I do a print_r - am I missing something?
$AllPupils = array();
foreach($reportsResult->getRecords() as $reportRecord)
{
$Pupil = new Pupil();
$Pupil->FamID = $reportRecord->getField('FName');
$Pupil->ChildName = $reportRecord->getField('SName');
array_push($AllPupils, $Pupil);
}
json_encode($AllPupils);
Everytime your foreach loop starts again, it will override your $Pupil variable.
Try an array instead:
$Pupil = array()
$i = 0;
foreach($reportsResult->getRecords() as $reportRecord) {
$Pupil[$i] = new Pupil();
$Pupil[$i]->FirstName = $reportRecord->getField('FName');
$Pupil[$i]->LastName = $reportRecord->getField('SName');
$i++;
}
echo json_encode($Pupil);
Edit: mikemackintosh's solution should also work and could be a little bit faster (depending on the size of your foreach loop).
To display the results you need to echo your data (not only json_encode).
You will probably run into issues since json_encode wont handle the whole object. for that, you may want to serialize the $Pupil object.
Something like below may work for you though. It will assign the values to a returned array, which will allow json_encode to execute gracefully:
class Pupil {
public $FirstName = "";
public $LastName = "";
public function getAttr(){
return array("FirstName" => $this->FirstName, "LastName" => $this->LastName);
}
}
$json = array();
foreach($reportsResult->getRecords() as $reportRecord) {
$Pupil = new Pupil();
$Pupil->FirstName = $reportRecord->getField('FName');
$Pupil->LastName = $reportRecord->getField('SName');
$json[] = $Pupil->getAttr();
}
echo json_encode($json);
I am not sure why you have that class defined, but you know what in your for each have something like
foreach ($reportsResult->getRecords() as $key => $record) {
$data[$key]['firstname'] = $record->getField('Fname');
$data[$key]['lastname'] = $record->getField('Sname');
}
And then you can check the final array using print_r
and while output you can simply do a print json_encode($data) and it will give you a json string of all the items in the data array.
In php (at least), json_encode takes an array as parameter.
Therefore you should add a constructor to your class
function __construct($first, $last)
{
this.$FirstName = $first;
this.$LastName = $last;
}
and one for getting the full name as an array, ready to be jsoned
function getNameArray()
{
$nameArray = array();
$nameArray['firstName'] = this.$FirstName;
$nameArray['lastName'] = this.$LastName;
return $nameArray;
}
then in that foreach you build another array with all the pupils
$pupils = array();
foreach (bla bla)
{
$first = $reportRecord->getField('FName');
$last = $reportRecord->getField('SName');
$Pupil = new Pupil($first, $last);
array_push($pupils, $pupil.getNameArray());
}
finally, you have everything preped up
json_encode($pupils);
I'm sure there's other ways to debug your stuff, I use print_r mainly also.
I have the following PHP code:
$alignments = new StdClass();
if ($query->num_rows > 0)
{
foreach($query->result() as $row){
$alignments->{$row->table_id} = new StdClass();
$alignments->{$row->table_id}->table_id = isset($row->table_id)?$row->table_id:NULL;
$alignments->{$row->table_id}->title = isset($row->title)?$row->title:NULL;
$alignments->{$row->table_id}->url = isset($row->url)?$row->url:NULL;
$alignments->{$row->table_id}->state_id = isset($row->state_id)?$row->state_id:NULL;
$alignments->{$row->table_id}->cross_discipline_alignment = isset($row->cross_discipline_alignment)?$row->cross_discipline_alignment:NULL;
$alignments->{$row->table_id}->common_core = isset($row->common_core)?$row->common_core:NULL;
$alignments->{$row->table_id}->grade_level = isset($row->grade_level)?$row->grade_level:NULL;
$alignments->{$row->table_id}->indicators = new StdClass();
$alignments->{$row->table_id}->indicators->{$row->indicator_id} = new StdClass();
$alignments->{$row->table_id}->indicators->{$row->indicator_id}->indicator_id = isset($row->indicator_id)?$row->indicator_id:NULL;
$alignments->{$row->table_id}->indicators->{$row->indicator_id}->indicator = isset($row->indicator)?$row->indicator:NULL;
$alignments->{$row->table_id}->indicators->{$row->indicator_id}->key = isset($row->key)?$row->key:NULL;
$alignments->{$row->table_id}->indicators->{$row->indicator_id}->extra_data = isset($row->extra_data)?$row->extra_data:NULL;
$alignments->{$row->table_id}->indicators->{$row->indicator_id}->uri_k5 = isset($row->uri_k5)?$row->uri_k5:NULL;
$alignments->{$row->table_id}->indicators->{$row->indicator_id}->uri_612 = isset($row->uri_612)?$row->uri_612:NULL;
}
return $alignments;
}
The problem is that in the foreach loop if there are multiple items with the same $row->table_id then the last one in the loop is set (ignoring all others). I have tried the !isset($alignments->{row->table_id}) and it is still overriding. I am trying to say that if the variable of $alignments->{$row->table_id} exists, use it, if not, set it to a new StdClass()
Maybe you need to wrap your initialization like this:
if (!property_exists($alignment, $row->table_id)) {
$alignments->{$row->table_id} = new StdClass();
}
This is going to be my first time building an associative array. And if anyone can help me I would be grateful.
Basically, I want to loop through a directory of XML files. I want to find out if a certain editor was the editor of this file, and if the query is true, I would like to grab two pieces of information and achieve the result of an associate array with those two pieces of information for every case where the editor's name is found.
So here's what I have got so far:
function getTitleandID($editorName) {
$listofTitlesandIDs = array();
$filename = readDirectory('../editedtranscriptions');
foreach($filename as $file)
{
$xmldoc = simplexml_load_file("../editedtranscriptions/$file");
$xmldoc->registerXPathNamespace("tei", "http://www.tei-c.org/ns/1.0");
if ($editorName == $xmldoc->xpath("//tei:editor[#role='PeerReviewEditor']/text()"))
{
$title = $xmldoc->xpath("//tei:teiHeader/tei:title[1]");
$id = $xmldoc->xpath("//tei:text/tei:body/tei:div/#xml:id[1]");
$listofTitlesandIDs[] = //I don't know what to do here
}
else
{
$listofTitlesandIDs = null;
}
}
return $listofTitlesandIDs
}
This is about where I get stuck. I'd like to be able have $listofTitlesandIDs as an associative array where I could call up the values for two different keys, e.g. $listofTitlesandIDs['title'] and $listofTitlesandIDs[$id]
So that's about it. I'm grateful for any help you have time to provide.
Well I'm sure this is a little clumsy (the result of an amateur) but it has given me the result I want.
function getTitlesandIDs($EditorName) //gets titles and IDs for given author
{
$list = array();
$filename = readDirectory('../editedtranscriptions');
foreach($filename as $file)
{
$xmldoc = simplexml_load_file("../editedtranscriptions/$file");
$xmldoc->registerXPathNamespace("tei", "http://www.tei-c.org/ns/1.0");
$title = $xmldoc->xpath("//tei:teiHeader/tei:fileDesc/tei:titleStmt/tei:title[1]");
$id = $xmldoc->xpath("//tei:text/tei:body/tei:div/#xml:id");
$editorName = $xmldoc->xpath("//tei:editor[#role='PeerReviewEditor']/text()")
if ($editorName[0] == "$EditorName")
{
$result = array("title"=>$title[0], "id"=>$id[0]);
$list[] = $result;
}
}
return $list;
}
With this I can call the function $list = getTitlesandIDs('John Doe') and then access both the title and id in the associative array for each instance. Like so:
foreach ($list as $instance)
{
echo $instance['title'];
echo $instance['id'];
}
Maybe that will help somebody some day -- let me know if you have any advice on making this more elegant.
$listofTitlesandIDs[$id] = $title;
You should loop over the array then using the foreach loop.
I've got a, I think fairly easy question, but this is bugging me for a while now. So I figured, maybe I can get some help here.
Since recursive functions are always a bit tricky, and sometimes a bit unclear to me, I keep struggling to create a nice working solution to get my menudata.
In one of my classes I have this function, which gives me all menu-items recursively.
The thing I want is to determine at which recursion level a certain object was retrieved so I can create a nicely looking HTML output with indents for the levels of nesting.
public function GetObjectList($parentID = 0, $objectlist = null)
{
if(is_null($objectlist))
{
$objectlist = new ObjectList("Model_Navigation");
}
$query = MySQL::Query("SELECT * FROM `Navigation` WHERE `WebsiteID` = ".SITE_ID. " AND `LanguageID` = ".LANG_ID." AND `ParentID` = ".$parentID);
while($result = MySQL::FetchAssoc($query))
{
$object = new Model_Navigation();
$object->ID = $result["ID"];
$object->WebsiteID = $result["WebsiteID"];
$object->LanguageID = $result["LanguageID"];
$object->ParentID = $result["ParentID"];
$object->Name = $result["Name"];
$object->Page = Model_Page::GetObjectByID($result["PageID"]);
$object->ExternalURL = $result["ExternalURL"];
$object->Index = $result["Index"];
$object->Level = [here lies my problem];
$objectlist->Add($object);
self::GetObjectList($object->ID, $objectlist);
}
return $objectlist;
}
public function GetObjectList($parentID = 0, $objectlist = null, $level = 1)
{
if(is_null($objectlist))
{
$objectlist = new ObjectList("Model_Navigation");
}
$query = MySQL::Query("SELECT * FROM `Navigation` WHERE `WebsiteID` = ".SITE_ID. " AND `LanguageID` = ".LANG_ID." AND `ParentID` = ".$parentID);
while($result = MySQL::FetchAssoc($query))
{
$object = new Model_Navigation();
$object->ID = $result["ID"];
$object->WebsiteID = $result["WebsiteID"];
$object->LanguageID = $result["LanguageID"];
$object->ParentID = $result["ParentID"];
$object->Name = $result["Name"];
$object->Page = Model_Page::GetObjectByID($result["PageID"]);
$object->ExternalURL = $result["ExternalURL"];
$object->Index = $result["Index"];
$object->Level = $level;
$objectlist->Add($object);
self::GetObjectList($object->ID, $objectlist, $level+1);
}
return $objectlist;
}
Why don't you just add a parameter to the function call that stores the number of calls. At the first call just make that 0, increment the value inside the function and use it in the recursive call.