denhamd2 Posted November 2, 2013 Share Posted November 2, 2013 Hi, I have an XML files of sports events (see below). Some of the events have the same match name, so I've put everything into an array and then tried to match them using matchname as a key. The XML looks like this: <match><sportname>Football</sportname><tournamentname>Red League</tournamentname><thetime>201311021245</thetime><matchname dateandtime="1383396300">Town Rovers vs Chanel</matchname><linkset><link lang="en" kbps="300" channelname="Link 1">link1.html</link><link lang="en" kbps="350" channelname="Link 2">link2.html</link></linkset></match> <match><sportname>Football</sportname><tournamentname>Red League</tournamentname><thetime>201311021245</thetime><matchname dateandtime="1383396300">Town Rovers vs Chanel</matchname><linkset><link lang="en" kbps="320" channelname="Link 3">link3c.html</link><link lang="en" kbps="320" channelname="Link 3">link4.html</link></linkset></match> Here's my PHP code (I'm pulling in the XML file using SimpleXML)... $xml = simplexml_load_file('test3.xml'); $aCopy = array(); foreach ($xml->match AS $match) { if (!isset($aCopy[(string)$match->matchname])) { $aCopy[(string)$match->matchname] = $match; } else { foreach ($match->linkset->link AS $link) { $aCopy[(string)$match->matchname]->linkset->addChild('link', $link); } } } The code above seems to have gotten me 80% of the way in that they are matching ok and the links output ok. But the weird thing is the attributes on the 2nd instance of the match aren't outptting... Link 1 en 300 link1.html Link 2 en 350 link2.html [blank] [blank] [blank] link3.html [blank] [blank] [blank] link4.hmtl (Where [blank] is supposed to be the channelname, lang and kbps outputted attributes) Any suggestions on what I might be doing wrong here? Thanks in advance for any help you can offer. Quote Link to comment Share on other sites More sharing options...
Barand Posted November 2, 2013 Share Posted November 2, 2013 does this help? $xml = simplexml_load_string($str); $channelname = "CHANNEL"; // get from xml feed $lang = "LANG"; // get from xml feed $kbps = "KBPS"; // get from xml feed $acopy = array(); foreach ($xml->match as $match) { foreach ($match->linkset->link as $link) { $acopy[(string)$match->matchname][] = array($channelname, $lang, $kbps, (string)$link); } } echo '<pre>',print_r($acopy, true),'</pre>'; RESULT Array ( [Town Rovers vs Chanel] => Array ( [0] => Array ( [0] => CHANNEL [1] => LANG [2] => KBPS [3] => link1.html ) [1] => Array ( [0] => CHANNEL [1] => LANG [2] => KBPS [3] => link2.html ) [2] => Array ( [0] => CHANNEL [1] => LANG [2] => KBPS [3] => link3c.html ) [3] => Array ( [0] => CHANNEL [1] => LANG [2] => KBPS [3] => link4.html ) ) ) Quote Link to comment Share on other sites More sharing options...
denhamd2 Posted November 3, 2013 Author Share Posted November 3, 2013 (edited) Thanks for your reply - I've updated my code. For the attributes in the array you pasted, will the channel name output as "Link 3" or literally "CHANNEL"? Also, I'm not able to output my HTML for some reason. Here is my code: foreach ($acopy AS $thematches) { $singlematchname = strtolower($thematches->matchname); // FORMAT $singlematchlinks = ''; // LOOP THROUGH ALL LINKS foreach ($thematches->linkset->link AS $link) { $singlematchlinks .= '<div class="matchrow"><div class="channelname">'.$link["channelname"].'</div><div class="language">'.$link["lang"].'</div><div class="kbps">'.$link["kbps"].'</div><div class="link"><a href="'.$link.'" target="_blank">Watch</a></div><div class="clearb"></div></div>'; } echo '<h5>'.$singlematchname.'</h5>'.$singlematchlinks; } This gives the error: Warning: Invalid argument supplied for foreach() in /home/freefoot/public_html/newsite/read_test2.php on line 55 Line 55 starts with: foreach ($thematches->linkset->link AS $link) Any idea what I might be doing wrong? Edited November 3, 2013 by denhamd2 Quote Link to comment Share on other sites More sharing options...
alpine Posted November 3, 2013 Share Posted November 3, 2013 $thematches->linkset->link is obviously not an array (anymore), thats why its flagged as invalid Simple test: if(is_array($thematches->linkset->link)){ echo '<p>is array:</p>'; print_r($thematches->linkset->link); } else{ echo '<p>is not an array:</p>'; echo $thematches->linkset->link; } Quote Link to comment Share on other sites More sharing options...
denhamd2 Posted November 3, 2013 Author Share Posted November 3, 2013 Thanks. Any idea how I'd fix this? Quote Link to comment Share on other sites More sharing options...
Barand Posted November 3, 2013 Share Posted November 3, 2013 I hardcoded Channel, Lang and Kbps as they were not in the XML that you posted Quote Link to comment Share on other sites More sharing options...
denhamd2 Posted November 4, 2013 Author Share Posted November 4, 2013 Hi, In the XML I posted, you can see them as attributes: <link lang="en" kbps="300" channelname="Link 1"> Any idea how I'd pull them out to replace your hard coded values? Quote Link to comment Share on other sites More sharing options...
Barand Posted November 4, 2013 Share Posted November 4, 2013 Sorry, missed those $xml = simplexml_load_string($str); $acopy = array(); foreach ($xml->match as $match) { foreach ($match->linkset->link as $link) { $acopy[(string)$match->matchname][] = array( (string)$link['channelname'], (string)$link['lang'], (string)$link['kbps'], (string)$link ); } } echo '<pre>',print_r($acopy, true),'</pre>'; Quote Link to comment Share on other sites More sharing options...
denhamd2 Posted November 5, 2013 Author Share Posted November 5, 2013 Thats brilliant thanks! The only things that are missing are the sportname, tournamentname and thetime - any idea how to include those in the array? Thanks again for your help Quote Link to comment Share on other sites More sharing options...
Barand Posted November 5, 2013 Share Posted November 5, 2013 do you mean something like this? $xml = simplexml_load_string($str); $acopy = array(); foreach ($xml->match as $match) { $acopy[(string)$match->matchname]['sportname'] = (string)$match->sportname; $acopy[(string)$match->matchname]['tournamentname'] = (string)$match->tournamentname; $acopy[(string)$match->matchname]['time'] = (string)$match->thetime; foreach ($match->linkset->link as $link) { $acopy[(string)$match->matchname]['links'][] = array( (string)$link['channelname'], (string)$link['lang'], (string)$link['kbps'], (string)$link ); } } echo '<pre>',print_r($acopy, true),'</pre>'; result Array ( [Town Rovers vs Chanel] => Array ( [sportname] => Football [tournamentname] => Red League [time] => 201311021245 [links] => Array ( [0] => Array ( [0] => Link 1 [1] => en [2] => 300 [3] => link1.html ) [1] => Array ( [0] => Link 2 [1] => en [2] => 350 [3] => link2.html ) [2] => Array ( [0] => Link 3 [1] => en [2] => 320 [3] => link3c.html ) [3] => Array ( [0] => Link 3 [1] => en [2] => 320 [3] => link4.html ) ) ) ) Quote Link to comment Share on other sites More sharing options...
denhamd2 Posted November 10, 2013 Author Share Posted November 10, 2013 This is perfect, thanks so much again. In terms of outputting it in HTML, I'm trying to output it like below: Football Red League - Town Rovers vs Chanel Link 1: 300: en: link1.html Link 2: 300: en: link2.html Link 3: 300: en: link3.html Link 4: 300: en: link4.html Blue League - Blue United vs FC Turf Link 5: 200: en: link5.html Link 6: 300: de: link6.html Link 7: 500: en: link7.html Link 8: 300: en: link8.html I just can't get my head around how to use the perfectly formatted array you gave me to do this. I just keep getting errors. Any last help you could offer would be hugely appreciated! Quote Link to comment Share on other sites More sharing options...
Barand Posted November 10, 2013 Share Posted November 10, 2013 I have altered the structure of the array so they are grouped by sportname/tournamentname/matchname. Makes it nice and easy to loop through the structure. $xml = simplexml_load_string($str); $acopy = array(); /********************************** * Build the array ***********************************/ foreach ($xml->match as $match) { $acopy[(string)$match->sportname][(string)$match->tournamentname][(string)$match->matchname]['time'] = (string)$match->thetime; foreach ($match->linkset->link as $link) { $acopy[(string)$match->sportname][(string)$match->tournamentname][(string)$match->matchname]['links'][] = array( (string)$link['channelname'], (string)$link['kbps'], (string)$link['lang'], (string)$link ); } } /********************************** * Output the array ***********************************/ foreach ($acopy as $sportname => $sportarray) { echo "$sportname<br><br>"; foreach ($sportarray as $tournament => $tournarray) { foreach ($tournarray as $match => $matcharray) { echo "$tournament - $match<br>"; foreach ($matcharray['links'] as $linkarray) { echo join(' : ', $linkarray) . '<br>'; } echo '<br>'; } } } Quote Link to comment Share on other sites More sharing options...
denhamd2 Posted December 29, 2013 Author Share Posted December 29, 2013 Excellent, this works a charm - thanks so much! One last thing ... I'm trying to output the time and date from the XML node "thetime" in the format: Blue League - Blue United vs FC Turf - 29th December 2013, 16:00 Any idea how I'd do this? Thanks again Quote Link to comment Share on other sites More sharing options...
Barand Posted December 29, 2013 Share Posted December 29, 2013 /********************************** * Output the array ***********************************/ foreach ($acopy as $sportname => $sportarray) { echo "$sportname<br><br>"; foreach ($sportarray as $tournament => $tournarray) { foreach ($tournarray as $match => $matcharray) { $dt = date('jS F Y, H:i', strtotime($matcharray['time'])); // added echo "$tournament - $match - $dt<br>"; // changed foreach ($matcharray['links'] as $linkarray) { echo join(' : ', $linkarray) . '<br>'; } echo '<br>'; } } } Quote Link to comment Share on other sites More sharing options...
denhamd2 Posted January 3, 2014 Author Share Posted January 3, 2014 Many thanks that's brilliant I just realised my list of events is not outputting in order of nearest date and time first... would you have any idea how to do this please? I promise this is the last question - thanks so much again! Quote Link to comment Share on other sites More sharing options...
Barand Posted January 3, 2014 Share Posted January 3, 2014 (edited) Given there is only one date value in the trivial amount of data provided then there is no way to test. However, try it with this extra line /********************************** * Output the array ***********************************/ foreach ($acopy as $sportname => $sportarray) { echo "$sportname<br><br>"; foreach ($sportarray as $tournament => $tournarray) { uasort($tournarray, function($a,$b){return strcmp($a['time'], $b['time']);}); // ADD foreach ($tournarray as $match => $matcharray) { $dt = date('jS F Y, H:i', strtotime($matcharray['time'])); echo "$tournament - $match - $dt<br>"; foreach ($matcharray['links'] as $linkarray) { echo join(' : ', $linkarray) . '<br>'; } echo '<br>'; } } } Edited January 3, 2014 by Barand Quote Link to comment Share on other sites More sharing options...
denhamd2 Posted January 4, 2014 Author Share Posted January 4, 2014 Thanks again for your help with this. It now filters by date but only within the scope of each tournament. Is it possible to do an absolute filter by date with all tournaments? Quote Link to comment Share on other sites More sharing options...
Barand Posted January 4, 2014 Share Posted January 4, 2014 Yes. Restructure the array or use a database. Quote Link to comment Share on other sites More sharing options...
denhamd2 Posted January 4, 2014 Author Share Posted January 4, 2014 So by re-structuring the array, do you mean having the top level be the date? Like so?... Array ( [201301041400] => Array { [Town Rovers vs Chanel] => Array ( [0] => Array ( [0] => CHANNEL [1] => LANG [2] => KBPS [3] => link1.html ) [1] => Array ( [0] => CHANNEL [1] => LANG [2] => KBPS [3] => link2.html ) [2] => Array ( [0] => CHANNEL [1] => LANG [2] => KBPS [3] => link3c.html ) [3] => Array ( [0] => CHANNEL [1] => LANG [2] => KBPS [3] => link4.html ) ) ) } Quote Link to comment Share on other sites More sharing options...
Barand Posted January 4, 2014 Share Posted January 4, 2014 Not necessarily. At present there is an array of sports. Each sport contains an array of leagues. Each league contains an array of matches So when an array of matches is sorted by time, it is within each league. It's matter of deciding at what level you want them sorted. But, instead of using XML as your data source it would be much better to load the data from the XML into a database and use the XML as a data transfer medium. Quote Link to comment Share on other sites More sharing options...
denhamd2 Posted January 4, 2014 Author Share Posted January 4, 2014 (edited) Thanks for this advice. Unfortunately I do not have access to a database, so I need to use just XML. The level I need them sorted is instead of within each league, it should be within each sport. How hard would it be to do this? Edited January 4, 2014 by denhamd2 Quote Link to comment Share on other sites More sharing options...
Solution Barand Posted January 4, 2014 Solution Share Posted January 4, 2014 This should do it $xml = simplexml_load_string($str); $acopy = array(); /********************************** * Build the array ***********************************/ foreach ($xml->match as $match) { $acopy[(string)$match->sportname][(string)$match->matchname]['time'] = (string)$match->thetime; $acopy[(string)$match->sportname][(string)$match->matchname]['tournament'] = (string)$match->tournamentname; foreach ($match->linkset->link as $link) { $acopy[(string)$match->sportname][(string)$match->matchname]['links'][] = array( (string)$link['channelname'], (string)$link['kbps'], (string)$link['lang'], (string)$link ); } } //echo '<pre>',print_r($acopy, true),'</pre>'; exit; /********************************** * Output the array ***********************************/ foreach ($acopy as $sportname => $sportarray) { echo "$sportname<br><br>"; uasort($sportarray, function($a,$b){return strcmp($a['time'], $b['time']);}); foreach ($sportarray as $match => $matcharray) { $dt = date('jS F Y, H:i', strtotime($matcharray['time'])); echo "{$matcharray['tournament']} - $match - $dt<br>"; foreach ($matcharray['links'] as $linkarray) { echo join(' : ', $linkarray) . '<br>'; } echo '<br>'; } } Quote Link to comment Share on other sites More sharing options...
denhamd2 Posted January 4, 2014 Author Share Posted January 4, 2014 Awesome! Works perfectly! Thanks so so much! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.