How do I convert result of SQL query to XML? - php

Basically, I'm taking an SQL query and converting it into a dynamic XML. I'm trying to create custom XML tags for elements that I obtain from my query, and I'd like to pick and choose which results from my query are used as XML elements.
In a perfect world, I'd like to be able to take each row that I get from the query and determine the XML properties. I'd like for this to be a loop, but I just can't seem to get it to work.
$sql = "SELECT
COUNT( l.log_id ) AS id,
l.status AS 'requestStatus',
d.firmname AS 'name',
DAY (FROM_UNIXTIME( l.time ) ) AS DAY,
WEEK( FROM_UNIXTIME( l.time ) ) AS week,
YEAR( FROM_UNIXTIME( l.time ) ) AS year
FROM $table_id1, $table_id2
WHERE
l.client = 'XXXXX' AND
l.time > 1 AND
l.work_id = d.subid AND
d.deleted = 0 AND
d.user_id = l.user_id
GROUP BY
YEAR( FROM_UNIXTIME( l.time ) ),
WEEK( FROM_UNIXTIME( l.time ) )
ORDER BY
week DESC";
$dbresult = mysql_query($sql);
// create a new XML document
$doc = new DomDocument('1.0', 'UTF-8');
$doc->formatOutput = true;
// create root node
$root = $doc->createElement('workResponse');
$root = $doc->appendChild($root);
$occ2 = $doc->createElement('contentResponses');
$occ2 = $root->appendChild($occ2);
// process one row at a time
while($row = mysql_fetch_assoc($dbresult)) {
// add node for each row
$occ = $doc->createElement("contentResponse");
$occ = $root->appendChild($occ);
// add a child node for each field
foreach ($row as $fieldname => $fieldvalue) {
$child = $doc->createElement($fieldname);
$child = $occ->appendChild($child);
$value = $doc->createTextNode($fieldvalue);
$value = $child->appendChild($value);
} // foreach
}// while
// get completed xml document
$xml_string = $doc->saveXML();
echo $xml_string;
?>

First, I suggest not using mysql_* functions. They are deprecated and going away.
Dom extension seems to be overkill in this situation. I prefer to use SimpleXML when I can.
<?php
$dbh = new PDO('mysql:host=localhost;dbname=test','username','password');
$sxe = new SimpleXMLElement('<workResponse></workResponse>');
$sxe_crs = $sxe->addChild('contentResponses');
function array_walk_simplexml(&$value, $key, &$sx) {
$sx->addChild($key, $value);
}
$stmt = $dbh->query('SELECT * FROM sometable');
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$sx_cr = $sxe_crs->addChild('contentResponse');
array_walk($row, 'array_walk_simplexml', $sx_cr);
}
echo $sxe->asXML();
If you want to "pretty print" the XML (admire your work?), then you'll need to use the Dom extension.
$dom_sxe = dom_import_simplexml($sxe);
$dom = new DOMDocument('1.0');
$dom->formatOutput = true;
$dom_sxe = $dom->importNode($dom_sxe, true);
$dom_sxe = $dom->appendChild($dom_sxe);
echo $dom->saveXML();

XML_Serializer is very useful for php pear users

Related

viewing XML data if attribute value equals variable value

I'm stuck on something extremely simple.
Here is my xml feed:
http://xml.betfred.com/Horse-Racing-Daily.xml
Here is my code
<?php
function HRList5($viewbets) {
$xmlData = 'http://xml.betfred.com/Horse-Racing-Daily.xml';
$xml = simplexml_load_file($xmlData);
$curdate = date('d/m/Y');
$new_array = array();
foreach ($xml->event as $event) {
if($event->bettype->attributes()->bettypeid == $viewbets){//$_GET['evid']){
// $eventid = $_GET['eventid'];
// if ($limit == $c) {
// break;
// }
// $c++;
$eventd = substr($event->attributes()->{'date'},6,2);
$eventm = substr($event->attributes()->{'date'},4,2);
$eventy = substr($event->attributes()->{'date'},0,4);
$eventt = $event->attributes()->{'time'};
$eventid = $event->attributes()->{'eventid'};
$betname = $event->bettype->bet->attributes()->{'name'};
$bettypeid = $event->bettype->attributes()->{'bettypeid'};
$betprice = $event->bettype->bet->attributes()->{'price'};
$betid = $event->bettype->bet->attributes()->{'id'};
$new_array[$betname.$betid] = array(
'betname' => $betname,
'viewbets' => $viewbets,
'betid' => $betid,
'betname' => $betname,
'betprice' => $betprice,
'betpriceid' => $event->bettype->attributes()->{'betid'},
);
}
ksort($new_array);
$limit = 10;
$c = 0;
foreach ($new_array as $event_time => $event_data) {
// $racedate = $event_data['eventy'].$event_data['eventm'].$event_data['eventd'];
$today = date('Ymd');
//if($today == $racedate){
// if ($limit == $c) {
// break;
//}
//$c++;
$replace = array("/"," ");
// $eventname = str_replace($replace,'-', $event_data['eventname']);
//$venue = str_replace($replace,'-', $event_data['venue']);
echo "<div class=\"units-row unit-100\">
<div class=\"unit-20\" style=\"margin-left:0px;\">
".$event_data['betprice']."
</div>
<div class=\"unit-50\">
".$event_data['betname'].' - '.$event_data['betprice']."
</div>
<div class=\"unit-20\">
<img src=\"betnow.gif\" ><br />
</div>
</div>";
}
}//echo "<strong>View ALL Horse Races</strong> <strong>>></strong>";
//var_dump($event_data);
}
?>
Now basically the XML file contains a list of horse races that are happening today.
The page I call the function on also declares
<?php $viewbets = $_GET['EVID'];?>
Then where the function is called I have
<?php HRList5($viewbets);?>
I've just had a play around and now it displays the data in the first <bet> node
but the issue is it's not displaying them ALL, its just repeating the 1st one down the page.
I basically need the xml feed queried & if the event->bettype->attributes()->{'bettypeid'} == $viewbets I want the bet nodes repeated down the page.
I don't use simplexml so can offer no guidance with that - I would say however that to find the elements and attributes you need within the xml feed that you ought to use an XPath query. The following code will hopefully be of use in that respect, it probably has an easy translation into simplexml methods.
Edit: Rather than targeting each bet as the original xpath did which then caused issues, the following should be more useful. It targets the bettype and then processes the childnodes.
/* The `eid` to search for in the DOM document */
$eid=25573360.20;
/* create the DOM object & load the xml */
$dom=new DOMDocument;
$dom->load( 'http://xml.betfred.com/Horse-Racing-Daily.xml' );
/* Create a new XPath object */
$xp=new DOMXPath( $dom );
/* Search the DOM for nodes with particular attribute - bettypeid - use number function from XSLT to test */
$oCol=$xp->query('//event/bettype[ number( #bettypeid )="'.$eid.'" ]');
/* If the query was successful there should be a nodelist object to work with */
if( $oCol ){
foreach( $oCol as $node ) {
echo '
<h1>'.$node->parentNode->getAttribute('name').'</h1>
<h2>'.date('D, j F, Y',strtotime($node->getAttribute('bet-start-date'))).'</h2>';
foreach( $node->childNodes as $bet ){
echo "<div>Name: {$bet->getAttribute('name')} ID: {$bet->getAttribute('id')} Price: {$bet->getAttribute('price')}</div>";
}
}
} else {
echo 'XPath query failed';
}
$dom = $xp = $col = null;

Xpath to parse xml and input in mysql

I'm trying to use xpath in conjunction with DOMDocument to try and parse my xml and insert into a table.
All my variables are inserting correctly other than $halftimescore - why is this?
Here is my code:
<?php
define('INCLUDE_CHECK',true);
require 'db.class.php';
$dom = new DOMDocument();
$dom ->load('main.xml');
$xpath = new DOMXPath($dom);
$queryResult = $xpath->query('//live/Match/Results/Result[#name="HT"]');
foreach($queryResult as $resulty) {
$halftimescore=$resulty->getAttribute("value");
}
$Match = $dom->getElementsByTagName("Match");
foreach ($Match as $match) {
$matchid = $match->getAttribute("id");
$home = $match->getElementsByTagName("Home");
$hometeam = $home->item(0)->getAttribute("name");
$homeid = $home->item(0)->getAttribute("id");
$away = $match->getElementsByTagName("Away");
$awayid = $away->item(0)->getAttribute("id");
$awayteam = $away->item(0)->getAttribute("name");
$leaguename = $match->getElementsByTagName("league");
$league = $leaguename->item(0)->nodeValue;
$leagueid = $leaguename->item(0)->getAttribute("id");
foreach ($match->getElementsByTagName('Result') as $result) {
$resulttype = $result->getAttribute("name");
$score = $result->getAttribute("value");
$scoreid = $result->getAttribute("value");
}
mysql_query("
INSERT INTO blabla
(home_team, match_id, ht_score, away_team)
VALUES
('".$hometeam."', '".$matchid."', '".$halftimescore."', '".$awayteam."')
");
}
Because you populated $halftimescore outside the main loop, in a loop of its own, it will only have one value (the last value) because each iteration overwrites the previous.
What you need to do instead is run the XPath query within the main loop, with a base node of the current node, like this:
// ...
$xpath = new DOMXPath($dom);
/*
Remove these lines from here...
$queryResult = $xpath->query('//live/Match/Results/Result[#name="HT"]');
foreach($queryResult as $resulty) {
$halftimescore=$resulty->getAttribute("value");
}
*/
$Match = $dom->getElementsByTagName("Match");
foreach ($Match as $match) {
// and do the query here instead:
$result = $xpath->query('./Results/Result[#name="HT"]', $match);
if ($result->length < 1) {
// handle this error - the node was not found
}
$halftimescore = $result->item(0)->getAttribute("value");
// ...

How to put XML content in reverse order?

I tried a few solutions already posted here, but nothing seems to work. That might be, because I am really not that familiar with php or xml. I just need to output xml for xcoding. So hopefully someone can shed some light, on how I can reverse the order of my xml, so that the last entry is on top.
My last try what with:
$query = array_reverse($doc->xpath('query'));
but it did not like it ,e.g. it did not work.
So here is my code in order to create my xml document:
<?php
if(!$dbconnect = mysql_connect('localhost', '-', '-')) {
echo "Connection failed to the host 'localhost'.";
exit;
} // if
if (!mysql_select_db('-')) {
echo "Cannot connect to database '-'";
exit;
} // if
$table_id = 'table1';
$query = "SELECT Name,Age,Sex FROM $table_id";
$dbresult = mysql_query($query, $dbconnect);
// create a new XML document
$doc = new DomDocument('1.0');
// create root node
$root = $doc->createElement('root');
$root = $doc->appendChild($root);
// process one row at a time
while($row = mysql_fetch_assoc($dbresult)) {
// add node for each row
$occ = $doc->createElement($table_id);
$occ = $root->appendChild($occ);
// add a child node for each field
foreach ($row as $fieldname => $fieldvalue) {
$child = $doc->createElement($fieldname);
$child = $occ->appendChild($child);
$value = $doc->createTextNode($fieldvalue);
$value = $child->appendChild($value);
} // foreach
} // while
// get completed xml document
$xml_string = $doc->saveXML();
$doc->save("yolo.xml")
//echo $xml_string;
?>
The best thing to do is to issue an SQL query which returns results in the order you want. The SQL query you have here has no ORDER BY clause, so results come back in no particular order.
However, you can also reverse the order of results as you add them to your XML document: instead of appending new child nodes for each row, prepend them. Replace this line:
$occ = $root->appendChild($occ);
With
$occ = $root->insertBefore($occ, $root->firstChild);
Also generally speaking it's best to finish building a tree of XML before you add it to the document.

how to pass a string variable as part of xml's name

I d like some guidance on how how to pass a string variable as part of an xml name.
I m running a mysql query according to the users form selection.Then i create an xml for the result.I d like to pass a variable as the name of the xml.How is this possible?
thats my working code:
$query = "SELECT * FROM $table WHERE diam = '$d' AND nom = '$n' AND dim = '$di' AND type = '$t'";
$query_result=mysql_query($query);
$num_rows = mysql_num_rows($query_result);
if($num_rows == 0) {
echo "bummer!";
} else {
#Creates a new DOMDocument
$doc = new DOMDocument("1.0", "utf-8");
#formats correctly the xml document
$doc->formatOutput = true;
#Create Parent Node
$parent_node = $doc->createElement('marker');
$parent_node = $doc->appendChild($parent_node);
#Row manip
while($row = mysql_fetch_assoc($query_result)) {
#adds node for each row
$row_node = $doc->createElement($table);
#appends the new node to the root
$occ = $parent_node->appendChild($row_node);
#add a child node for each field
foreach($row as $fieldname => $fieldvalue) {
$child = $doc->createElement($fieldname);
$child = $occ->appendChild($child);
$value = $doc->createTextNode($fieldvalue);
$value = $child->appendChild($value);
}
}
#saves generated domDocument into a file.
#If echo'ed outputs filezise in bytes
$xml_string = $doc->save('xmlOutput.xml');
}
instead of the hardcoded "xmlOutput" i d like to display ,lets say the diam column name.
Inside your loop where you loop through the result:
#Row manip
while($row = mysql_fetch_assoc($query_result))
you can access the value of the diam column by doing:
$diam = $row['diam'];
I noticed now that you might be asking for:
$filename = $d . '.xml';
$xml_string = $doc->save($filename);
Why dont you dynamically create the output file name? Something like this..
$ouputFile = $row['diam'] . '.xml';
$xml_string = $doc->save($outputFile);
If you want to dynamically create a filename then you can use the $d variable (which corresponds with your diam column).
$fileName = $d . '.xml';
$xml_string = $doc->save($fileName);

Converting Date Format

I have script which scrap/fetch html table data from another website. The website date format is 26/8/2011, How I can change it to this format 2011-12-13??
function createRSSFile($tag,$value,$data)
{
# this will return the each element with tag.
$tag=strtolower(str_replace(" ","_",$tag));
$tag=strtolower(str_replace(":","",$tag));
$tag=strtolower(str_replace("&","and",$tag));
$returnITEM = "<".$tag.">".htmlspecialchars(str_replace(" 00:00:00","",$value))."</".$tag.">";
return $returnITEM;
}
function fetchData($jobid) {
$html=file_get_contents('http://acbar.org/JobDetail.aspx?id='.$jobid);
$html=str_replace("<td></td>", "",$html);
$html=str_replace("<td style=\"font-size:8pt;font-weight:bold;\"></td>","<td style=\"font-size:8pt;font-weight:bold;\">Null</td>",$html);
$html=str_replace("<td style=\"font-size:8pt;font-weight:bold;\" colspan=\"2\" ></td>","<td style=\"font-size:8pt;font-weight:bold;\" colspan=\"2\" >Null</td>",$html);
$html=str_replace(" ", " ",$html);
$html=str_replace("?", "<br>",$html);
$html=str_replace("<br>", "_br_",$html);
$dom = new DOMDocument;
$dom->loadHTML( $html );
//echo $dom->saveHTML();
//exit;
$rows = array();
foreach( $dom->getElementsByTagName( 'tr' ) as $tr ) {
$cells = array();
foreach( $tr->getElementsByTagName( 'td' ) as $td ) {
if(trim($td->nodeValue)!='')
$cells[] = str_replace("_br_","<br>",trim($td->nodeValue));
}
if(sizeof($cells)>0)
$rows[] = $cells;
}
Could always strtotime the date passed, then format it however you wish with date, like so...
$timeToModify = strtotime($passedTime);
$formattedTime = date("Y-m-D", $timeToModify);

Categories