creating json or xml with mysql in php too slow - php

I am working on a project for a lecture at the university and I am searching for a solution for more than 2 weeks now, and I just can't get it right.
We have a project where we need to generate specific JSON or XML files to visualize them later with for example D3 or Sigma.
We have a mysql database and all the code is in Javascript (as you can see with the libraries) and we use pho to get the data from the database and to get it in the right format. Here is an example xml file I tried to create with php (it's a gexf-file for the visualization with Sigma, but it's just the same as xml):
<?xml version="1.0" encoding="UTF-8"?>
<gexf xmlns="http://www.gexf.net/1.2draft" version="1.2">
<meta lastmodifieddate="2009-03-20">
<creator>Gexf.net</creator>
<description>A hello world! file</description>
</meta>
<graph mode="static" defaultedgetype="directed">
<nodes>
<node id="0" label="Hello" />
<node id="1" label="Word" />
</nodes>
<edges>
<edge id="0" source="0" target="1" />
</edges>
</graph>
</gexf>
And Here is my php code where I tried to create the xml:
<?php
set_time_limit(500000000);
ini_set('memory_limit', '-1');
class XmlWriter2 {
var $xml;
var $indent;
var $stack = array();
function XmlWriter($indent = ' ') {
$this->indent = $indent;
$this->xml = '<?xml version="1.0" encoding="utf-8"?>'."\n";
}
function _indent() {
for ($i = 0, $j = count($this->stack); $i < $j; $i++) {
$this->xml .= $this->indent;
}
}
function push($element, $attributes = array()) {
$this->_indent();
$this->xml .= '<'.$element;
foreach ($attributes as $key => $value) {
$this->xml .= ' '.$key.'="'.htmlentities($value).'"';
}
$this->xml .= ">\n";
$this->stack[] = $element;
}
function element($element, $content, $attributes = array()) {
$this->_indent();
$this->xml .= '<'.$element;
foreach ($attributes as $key => $value) {
$this->xml .= ' '.$key.'="'.htmlentities($value).'"';
}
$this->xml .= '>'.htmlentities($content).'</'.$element.'>'."\n";
}
function emptyelement($element, $attributes = array()) {
$this->_indent();
$this->xml .= '<'.$element;
foreach ($attributes as $key => $value) {
$this->xml .= ' '.$key.'="'.htmlentities($value).'"';
}
$this->xml .= " />\n";
}
function pop() {
$element = array_pop($this->stack);
$this->_indent();
$this->xml .= "</$element>\n";
}
function getXml() {
return $this->xml;
}
}
/*
$xml = new XmlWriter2();
$array = array(
array('monkey', 'banana', 'Jim'),
array('hamster', 'apples', 'Kola'),
array('turtle', 'beans', 'Berty'),
);
$xml->push('zoo');
foreach ($array as $animal) {
$xml->push('animal', array('species' => $animal[0]));
$xml->element('name', $animal[2]);
$xml->element('food', $animal[1]);
$xml->pop();
}
$xml->pop();
print $xml->getXml();
<?xml version="1.0" encoding="utf-8"?>
<zoo>
<animal species="monkey">
<name>Jim</name>
<food>banana</food>
</animal>
<animal species="hamster">
<name>Kola</name>
<food>apples</food>
</animal>
<animal species="turtle">
<name>Berty</name>
<food>beans</food>
</animal>
</zoo>
*/
mysql_connect("127.0.0.1", "root", "manager") or die(mysql_error());
mysql_select_db("enrondata") or die(mysql_error());
$data1 = mysql_query("SELECT DISTINCT sId FROM mailToId WHERE date
BETWEEN '01.06.2002' AND '30.06.2002' UNION SELECT DISTINCT rId FROM
mailToId WHERE date BETWEEN '01.06.2002' AND '30.06.2002'") or die
(mysql_error());
$data2 = mysql_query("SELECT sender, recipient, count(*) AS numMails
FROM mailTo WHERE date BETWEEN '01.06.2002' AND '30.06.2002' GROUP
BY sender, recipient") or die (mysql_error());
$users = array();
$id = 0;
while($tmpUsers = mysql_fetch_array($data1)){
$tmpArray['id'] = $tmpUsers['sId'];
$user = mysql_query("SELECT email FROM users WHERE id=".$tmpUsers['sId']);
while($tmpUser = mysql_fetch_array($user)){
$tmpArray['email'] = $tmpUser['email'];
}
array_push($users, $tmpArray);
}
$xml = new XmlWriter2();
$xml->push('gexf', array('xmlns' => 'http://www.gexf.net/1.2draft" version="1.2'));
$xml->push('meta', array('lastmodifieddate' => '2009-03-20'));
$xml->element('creator', 'Gexf.net');
$xml->element('description', 'A hello world! file');
$xml->pop();
$xml->push('graph', array('mode' => 'static', 'defaultedgetype' => 'directed'));
$xml->push('nodes');
for($i = 0; $i < count($users); $i++){
$xml->push('node', array('id' => $users['id'],
'label' => $users['email']));$xml->pop();
}
$xml->pop();
$xml->push('edges');
while($tmp = mysql_fetch_array($data2)){
$xml->push('edge', array('id' => id,
'source' => $tmp['sender'], 'target' => $tmp['recipient'], 'weight'
=> $tmp['numMails']));$xml->pop();
$id++;
}
$xml->pop();
$xml->pop();
$xml->pop();
print $xml->getXml();
?>
And it works, the code is correct, but it takes hours. Really, even after 30min it is not finished doing all that. And I have no idea how to improve it and get it very fast. Or is there another possiblity to get the data from the mysql database in the right format without using php?
Please help me. My deadline is really close and I have no ideas and didn't find anything on the web that fits my problem.

So you doing over 500 000 querys, that a big overhead,
try just join in the email in the first query:
/* puggan added left join email */
$data1 = mysql_query("SELECT DISTINCT mailToId.sId, users.email FROM mailToId LEFT JOIN users ON (users.id = mailToId.sId) WHERE date BETWEEN '01.06.2002' AND '30.06.2002' UNION SELECT DISTINCT mailToId.rId, users.email FROM mailToId LEFT JOIN users ON (users.id = mailToId.rId) WHERE date BETWEEN '01.06.2002' AND '30.06.2002'") or die(mysql_error());
$data2 = mysql_query("SELECT sender, recipient, count(*) AS numMails FROM mailTo WHERE date BETWEEN '01.06.2002' AND '30.06.2002' GROUP BY sender, recipient") or die (mysql_error());
$users = array();
$id = 0;
while($tmpUsers = mysql_fetch_array($data1))
{
$tmpArray['id'] = $tmpUsers['sId'];
/* Puggan added: */
$tmpArray['email'] = $tmpUsers['email'];
// $user = mysql_query("SELECT email FROM users WHERE id=".$tmpUsers['sId']);
// while($tmpUser = mysql_fetch_array($user))
// {
// $tmpArray['email'] = $tmpUser['email'];
// }
array_push($users, $tmpArray);
}

Related

foreach loop in php needs debugging

While I had no success with php routing since is above my current knowledge I tried the implementation below:
$query = "SELECT * FROM persons WHERE SURNAME LIKE 'Ω%' ORDER BY SURNAME ASC;";
$result = mysqli_query($con, $query); //the selected query has 2 results!
/* determine number of rows result set */
$row_cnt = mysqli_num_rows($result);
printf("results (%d).", $row_cnt);
// Check result
// This shows the actual query sent to MySQL, and the error. Useful for debugging.
if (!$result) {
$message = 'Invalid query: ' . mysqli_error($con) . "\n";
$message .= 'Whole query: ' . $query;
die($message);
}
function generateTableFromResult($result) {
$x = 1;
$html = "<table>";
while($row = mysqli_fetch_array($result)) {
foreach($row as $column => $value) {
copy("persons.php","newfile".$x.".php");
$html.="<tr><th>".$column."</th><td>".$value."</td></tr>";
$myfile = fopen("newfile".$x.".php", "w") or die("Unable to open file!");
fwrite($myfile, $html);
}
$x++;
}
$html .= "</table>";
return $html;
}
// usage:
// ...
$result = mysqli_query($con, $query);
echo generateTableFromResult($result);`
The above script creates:
newfile1.php --> table + table (first + second result)
newfile2.php --> table + table (first + second result)
while I want:
newfile1.php --> table (first result)
newfile2.php --> table (second result)
What am I missing here?
edit:
example content of newfile1.php:
CODE_NO 12101
SURNAME ΩΝΑΣΗ
FIRST_NAME ΧΡΙΣΤΙΝΑ
SOURCE1 ΗΛΙΟΥ
SOURCE2
SOURCE3
PROV ΟΙΚΟΓΕΝΕΙΑΚΗ ΣΧΕΣΗ ΚΑΘΕΤΗ ΜΕ ΚΙΝΗΤΙΚΟΤΗΤΑ
SEX ΓΥΝΑΙΚΑ
BIRTH 1950
DEATH 1989
PLACE ΜΕΓΑΛΟ ΑΣΤΙΚΟ ΚΕΝΤΡΟ
REGION ΑΛΛΕΣ ΞΕΝΕΣ ΧΩΡΕΣ
EDUCATION ΜΕΤΑΠΤΥΧΙΑΚΕΣ ΣΠΟΥΔΕΣ
SPECIAL
WRITING
POLITICAL
MANAGERIAL
MILITARY
RELIGIOUS
SPIRITUAL
SCIENTIFIC
NOBLE ΝΑΙ
CULTURAL
FINANCIAL ΝΑΙ
CONSTITUTIONAL
OPPOSITION
PROF1 Επιχειρηματίας
PROF2 Νεώτερη αριστοκρατική ελίτ πλουτου
PROF3
PROF4
PROF5
PARTY
ACTIVITY1
ACTIVITY2
1800_1832
1833_1862
1863_1911
1912_1922
1923_1944
1945_1973 ΝΑΙ
1974_ ΝΑΙ
HIERARCHY Ανωτάτη Ελίτ
LEADERSHIP
HERE starts table 2 This is what tables look like. Remember I want each table to be written per person/file.
CODE_NO 12100
SURNAME ΩΝΑΣΗΣ
FIRST_NAME ΑΡΙΣΤΟΤΕΛΗΣ
SOURCE1 ΗΛΙΟΥ
SOURCE2 ΔΡΑΝΔΑΚΗ
SOURCE3 ΕΚΔΟΤΙΚΗ
PROV ΑΓΝΩΣΤΗ
SEX ΑΝΔΡΑΣ
BIRTH 1906
DEATH 1975
PLACE ΑΓΡΟΤΙΚΕΣ- ΝΗΣΙΩΤΙΚΕΣ
REGION ΜΙΚΡΑ ΑΣΙΑ
EDUCATION ΔΕΝ ΔΗΛΩΝΕΙ
SPECIAL
WRITING
POLITICAL
MANAGERIAL
MILITARY
RELIGIOUS
SPIRITUAL
SCIENTIFIC
NOBLE ΝΑΙ
CULTURAL
FINANCIAL ΝΑΙ
CONSTITUTIONAL
OPPOSITION
PROF1 Εφοπλιστής
PROF2 Νεώτερη αριστοκρατική ελίτ πλουτου
PROF3
PROF4
PROF5
PARTY
ACTIVITY1
ACTIVITY2
1800_1832
1833_1862
1863_1911
1912_1922
1923_1944 ΝΑΙ
1945_1973 ΝΑΙ
1974_
HIERARCHY Yψιστη Μορφή Ελίτ
LEADERSHIP
This should produce the output you want (from your comments):
function generateTableFromResult($result) {
$x = 1;
$html = '';
while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
// Add the open-table tag
$html = '<table>';
// Iterate through the columns and add them to our variable
foreach($row as $column => $value) {
$html .= "<tr><th>".$column."</th><td>".$value."</td></tr>";
}
// Add the close-table tag
$html .= "</table>";
// Now, since we've added all the rows for that person,
// create, populate and store the file
file_put_contents("newfile".$x.".php", $html);
// Increment $x before we jump to the next person
$x++;
}
// However, this will only return the table for the last person
return $html;
}
I also changed your fopen and copy (which didn't really make sense) to one simple command: file_put_contents()
A big shout out to #ishegg that helped narrow down the issue
By default, the fetch mode for mysqli_fetch_array() is MYSQLI_BOTH, which means it's getting each result in associative and numeric form. That, in addition to your double-looping over the results, gives you the results you're getting.
To fix it, you can use MYSQLI_ASSOC (or use mysqli_fetch_assoc()), so it only gets each row once.
function generateTableFromResult($result) {
$x = 1;
$html = "<table>";
while($row = mysqli_fetch_assoc($result)) {
foreach($row as $column => $value) {
copy("persons.php","newfile".$x.".php");
$html.="<tr><th>".$column."</th><td>".$value."</td></tr>";
$myfile = fopen("newfile".$x.".php", "w") or die("Unable to open file!");
fwrite($myfile, $html);
}
$x++;
}
$html.="</table>";
return $html;
}
Or, keeping your original function:
function generateTableFromResult($result) {
$x = 1;
$html = "<table>";
while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
foreach($row as $column => $value) {
copy("persons.php","newfile".$x.".php");
$html.="<tr><th>".$column."</th><td>".$value."</td></tr>";
$myfile = fopen("newfile".$x.".php", "w") or die("Unable to open file!");
fwrite($myfile, $html);
}
$x++;
}
$html.="</table>";
return $html;
}
Also, as #MagnusEriksson points out, you're appending the content to $html each time, so you will still get both results in the second file. To avoid this, put $html = "table"; inside the foreach loop:
function generateTableFromResult($result) {
$x = 1;
while($row = mysqli_fetch_array($result, MYSQLI_ASSOC)) {
foreach($row as $column => $value) {
copy("persons.php","newfile".$x.".php");
$html = "<table>";
$html.="<tr><th>".$column."</th><td>".$value."</td></tr>";
$html.="</table>";
$myfile = fopen("newfile".$x.".php", "w") or die("Unable to open file!");
fwrite($myfile, $html);
}
$x++;
}
return $html;
}

Generating XML from SQL using Mysqli

I'm trying to pull all the data from my users table and display it in XML format. The connection works fine and everything as I have a login and registration set up fine, but I can't seem to get this to display anything other than a white screen.
I've found lots of different tutorials on how to do it with mysql but not mysqli. what am i missing?
generatexml.php
<?php
include 'connection.php';
$xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
$root_element = $config['users'];
$xml .= "<$root_element>";
if ($result = $mysqli->query("SELECT * FROM users", MYSQLI_USE_RESULT)) {
while($row = $result->fetch_assoc())
{
$xml .= "<".$config['users'].">";
//loop through each key,value pair in row
foreach($result_array as $key => $value)
{
//$key holds the table column name
$xml .= "<$key>";
//embed the SQL data in a CDATA element to avoid XML entity issues
$xml .= "<![CDATA[$value]]>";
//and close the element
$xml .= "</$key>";
}
$xml.="</".$config['users'].">";
echo $xml;
}
}
?>
I struggle a lot to find out this solution in mysqli format but nowhere i found the solution. Below is the solution i figured. Run this demo and map it your requirement, surely it will help.
<?php
//Create file name to save
$filename = "export_xml_".date("Y-m-d_H-i",time()).".xml";
$mysql = new Mysqli('server', 'user', 'pass', 'database');
if ($mysql->connect_errno) {
throw new Exception(sprintf("Mysqli: (%d): %s", $mysql->connect_errno, $mysql->connect_error));
}
//Extract data to export to XML
$sqlQuery = 'SELECT * FROM t1';
if (!$result = $mysql->query($sqlQuery)) {
throw new Exception(sprintf('Mysqli: (%d): %s', $mysql->errno, $mysql->error));
}
//Create new document
$dom = new DOMDocument;
$dom->preserveWhiteSpace = FALSE;
//add table in document
$table = $dom->appendChild($dom->createElement('table'));
//add row in document
foreach($result as $row) {
$data = $dom->createElement('row');
$table->appendChild($data);
//add column in document
foreach($row as $name => $value) {
$col = $dom->createElement('column', $value);
$data->appendChild($col);
$colattribute = $dom->createAttribute('name');
// Value for the created attribute
$colattribute->value = $name;
$col->appendChild($colattribute);
}
}
/*
** insert more nodes
*/
$dom->formatOutput = true; // set the formatOutput attribute of domDocument to true
// save XML as string or file
$test1 = $dom->saveXML(); // put string in test1
$dom->save($filename); // save as file
$dom->save('xml/'.$filename);
?>
If you have access to the mysql CLI, here's my quick hack for achieving this:
$sql = "SELECT * FROM dockcomm WHERE listname = 'roortoor'
and status IN ('P','E') and comm_type IN ('W','O')
and comm_period NOT IN ('1','2','3','4') order by comment_num";
$cmd = "/usr/bin/mysql -u<person> -h<host> -p<password> <database> --xml -e \"$sql\";";
$res = system($cmd ,$resval);
echo $res;
Here is a solution using php only. You where close to getting it right. This was the key part of the code that I changed "$row as $key => $data" used $row instead of $result_array, ie. iterate through row not the result_array (this contains the entire dataset). Hope this helps someone.
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
$value .="<record>\r\n";
//loop through each key,value pair in row
foreach($row as $key => $data)
{
//$key holds the table column name
$vals = "\t" . "<". $key . ">" . "<![CDATA[" . $data . "]]>" . "</" . $key . ">" . "\r\n";
$value = $value . $vals;
//echo $value;
}
$value .="</record>\r\n";
$count++;
}
} else {
// echo "0 results";
}
$conn->close();
One possible issue could be this line:
if ($result = $mysqli->query("SELECT * FROM users", MYSQLI_USE_RESULT)) {
Try the procedural approach instead of the object oriented approach. I do not know if $mysqli is defined in connection.php, but it is possible that you mixed it up.
if ($result = mysqli_query('SELECT * FROM users', MYSQLI_USE_RESULT)) {
This could resolve the white screen error.
I noticed two other things:
(1) One tiny effectiveness issue:
$xml = '<?xml version="1.0" encoding="UTF-8"?>';
So you do not need to escape every single quotation mark.
(2) One serious XML issue: The root element needs to be closed before you echo your $xml.
$xml .= "</$root_element>";
echo $xml;
Generally, for your purpose, it would be safer to use PHP's XMLWriter extension, as already proposed.

How to Create a secured API using PHP in xml format?

I have an ecommerce website in which regularly transactions keeps happening. Now we are developing an android app for the same. So I was asked to build an API using PHP. The API that i made was in xml format. But now since i will be sending he login credentials through it I am scared that someone would hack it. So can someone help me with it.
here is the way i had created the xml API using php..
<?php
include 'config.php';
include 'database.php';
$sqlCat = "select category_id,image,name from table" ;
$categories = DatabaseHandler::GetAll($sqlCat);
$xml = new DomDocument("1.0","UTF-8");
$content = $xml->createElement("content");
$content = $xml->appendChild($content);
foreach($categories as $category) {
$item = $xml->createElement("item");
$catName = $xml->createElement("catName",htmlspecialchars($category['name']));
$catName = $item->appendChild($catName);
$catImage = $xml->createElement("catImage",htmlspecialchars($category['image']));
$catImage = $item->appendChild($catImage);
$sql = "select image,name,model,price,quantity from table;
$results = DatabaseHandler::GetAll($sql);
foreach($results as $key=>$result) {
$product = $xml->createElement("product");
$product->setattribute('id',$key);
$model = $xml->createElement("model",$result['model']);
$model = $product->appendChild($model);
$name = $xml->createElement("name",htmlspecialchars($result['name']));
$name = $product->appendChild($name);
$image = $xml->createElement("image",htmlspecialchars($result['image']));
$image = $product->appendChild($image);
$price = $xml->createElement("price",$result['price']);
$price = $product->appendChild($price);
$product = $item->appendChild($product);
}
$item = $content->appendChild($item);
}
$xml->FormatOutput = true;
$output = $xml->saveXML();
$xml->save("categories.xml");
?>
and I get the xml in this form..
<content>
<item>
<catName>Comp</catName>
<catImage/>
<product id="0">
<model>156443</model>
<name>CD</name>
<image>109.jpg</image>
<price>48</price>
</product>
<product id="1">
<model>46876</model>
<name>memory card</name>
<image>81.jpg</image>
<price>12</price>
</product>
<product id="2">
<model>865793</model>
<name>drive</name>
<image>51.png</image>
<price>2</price>
</product>
</item>
</content>
Can someone tell whether the way i have generated API in XML format correct.
Dont make think too complex make it simple like following code
$con = mysql_connect("localhost","root","root") or die("could not connect".mysql_error());
//select your database table
mysql_select_db("android_maps", $con) or die("Could not select database".mysql_error());
//get your results with a mysql query
$result = mysql_query("SELECT gmaps.*, urls.* FROM gmaps, urls WHERE urls.idgmaps = gmaps.idgmaps") or die(mysql_error());
//run a while loop get your data.
while($location = mysql_fetch_array($result)) {
$output = '<?xml version="1.0" encoding="utf-8"?>';
$output .= '<data>';
$output .= "<lat>".$location['lat']."</lat>";
$output .= "<long>.".$location['lon']."</long>";
$output .= "<description>.".$location['description']."</description>";
$output .= '</data>';
print $output;
}
mysql_close($con);
}else{
echo "<h1>No results to show for you query</h1>";
}
for more info
http://teachingyou.net/php/php-api-development-dreaming-of-your-own-api-make-it-possible-today/

Convert PHP nested array to XML tree structure

I have following array in PHP and I want to convert it equivalent XML.
$data = array("VitalParameters"=>array(
"Details"=>array(
"PID"=>1234,
"OPID"=>1345
),
"Parameters"=>array(
"HR"=>112,
"SPO2"=>0
)));
Following XML tree structure which I expected
<VitalParameters>
<Details>
<PID>1234</PID>
<OPID>1345</OPID>
</Details>
<Parameters>
<HR>112</HR>
<SPO2>0</SPO2>
</Parameters>
</VitalParameters>
I tried many things but no luck. If any more information required just comment I will give additional information.
Try Array2XML (http://www.lalit.org/lab/convert-php-array-to-xml-with-attributes) this has worked for me.
$data = array(
"Details" => array(
"PID" => 1234,
"OPID" => 1345
),
"Parameters" => array(
"HR" => 112,
"SPO2" => 0
));
$xml = Array2XML::createXML('VitalParameters', $data)->saveXML();
echo $xml;
Output
<?xml version="1.0" encoding="UTF-8"?>
<VitalParameters>
<Details>
<PID>1234</PID>
<OPID>1345</OPID>
</Details>
<Parameters>
<HR>112</HR>
<SPO2>0</SPO2>
</Parameters>
</VitalParameters>
This should get you on the right track, probably needs some tuning though (especially in regards to keys aswell as checking if $arr is an array/object in the first place... this was just to show you how to recursively iterate them and print the data).
Also, this snippet does not support XML attributes in any way.
<?php
$data = array("VitalParameters"=>array(
"Details"=>array(
"PID"=>1234,
"OPID"=>1345
),
"Parameters"=>array(
"HR"=>112,
"SPO2"=>0
)));
function ArrayToXML($arr, $depth = 0, $maxDepth = 2)
{
$retVal = "";
foreach($arr as $key => $value)
{
$retVal .= "<" . $key . ">";
$type = gettype($value);
switch($type)
{
case "array":
case "object":
if ($depth < $maxDepth)
$retVal .= ArrayToXml($value, $depth+1, $maxDepth);
else
$retVal .= $type; // Depth >= MaxDepth, not iterating here
break;
case "boolean":
$retVal .= $value ? "true" : "false";
break;
case "resource":
$retVal .= "Resource";
case "NULL":
$retVal .= "NULL";
default:
$retVal .= $value;
}
$retVal .= "</" . $key . ">\n";
}
return $retVal;
}
echo ArrayToXML($data);
?>
Output:
<VitalParameters><Details><PID>1234</PID>
<OPID>1345</OPID>
</Details>
<Parameters><HR>112</HR>
<SPO2>0</SPO2>
</Parameters>
</VitalParameters>
I got solution like following code
<?php
header("Content-type: text/xml; charset=utf-8");
$data = array(
"Details" => array(
"PID" => "1234","OPID" => "1345"
),"Parameters" => array(
"HR" => "112","SPO2" => "0"
)
);
$domtree = new DOMDocument('1.0', 'UTF-8');
/* create the root element of the xml tree */
$xmlRoot = $domtree->createElement("VitalParameters");
/* append it to the document created */
$xmlRoot = $domtree->appendChild($xmlRoot);
foreach ($data as $key=>$value)
{
$currentElement= $domtree->createElement($key);
$currentElement= $xmlRoot->appendChild($currentElement);
if(is_array($value))
{
foreach ($value as $k=>$v)
{
$currentElement->appendChild($domtree->createElement($k,$v));
}
}
}
/* get the xml printed */
echo $domtree->saveXML();
Output
<VitalParameters>
<Details>
<PID>1234</PID>
<OPID>1345</OPID>
</Details>
<Parameters>
<HR>112</HR>
<SPO2>0</SPO2>
</Parameters>
</VitalParameters>
I think - this is must be more simple:
function arrayToXML($arr){
$s = "";
foreach($arr as $k => $v){
if(is_array($v)){$v = arrayToXML($v);}
$s .= "<{$k}>{$v}</{$k}>";
}
return $s;}

Getting element names/values with XML/Xpath/PHP

I have an XML schema that looks as follows:
<xml>
<user id="1">
<first_name>Bill</first_name>
<last_name>Steve</last_name>
<phone_numbers>
<work>xxx-xxx-xxxx</work>
<home>xxx-xxx-xxxx</home>
</phone_numbers>
</user>
<user id="2">
........
</user>
</xml>
Im working on parsing all of this information into PHP using DOM. Ex.
$userInfo = $doc->getElementsByTagName( "user" );
foreach($userInfo as $row)
{
$first_name = $row->getElementsByTagName("first_name");
}
When I try to nest this to select the phone numbers however I get an error. I've tried using XPath to select the phone numbers with equal problems. I tried something along the lines of
$userInfo = $doc->getElementsByTagName( "user" );
foreach($userInfo as $row)
{
$phoneInfo = $row->getElementsByTagName("phone_numbers");
foreach($phoneInfo as $row2)
{
$work = $row2->getElementsByTagName("work");
}
}
Im curious if Im doing something fundamentally wrong, or how to get this going. I've been tearing my hair out for a few hours now.
You can't get the value directly from a DOMNodeList Object, try this :
$userInfo = $doc->getElementsByTagName( "user" );
foreach($userInfo as $row)
{
$phoneInfo = $row->getElementsByTagName("phone_numbers");
foreach($phoneInfo as $row2)
{
// get the value from the first child
$work = $row2->getElementsByTagName("work")->item(0)->nodeValue;
$home = $row2->getElementsByTagName("home")->item(0)->nodeValue;
}
}
Well, you could switch it to SimpleXml which makes this type of parsing easier:
$userInfo = $doc->getElementsByTagName( "user" );
foreach ($userInfo as $user) {
$node = simplexml_import_dom($user);
$id = (string) $node['id'];
$first = (string) $node->first_name;
$last = (string) $node->last_name;
$workPhone = (string) $node->phone_numbers->work;
$homePhone = (string) $node->phone_numbers->home;
}
Now, in DomDocument, you could do this by using DomXpath:
$userInfo = $doc->getElementsByTagName( "user" );
$xpath = new DomXpath($doc);
foreach ($userInfo as $user) {
$id = $user->getAttribute('id');
$first = $xpath->query('//first_name', $user)->item(0)->textContent;
$last = $xpath->query('//last_name', $user)->item(0)->textContent;
$work = $xpath->query('//phone_numbers/work', $user)->item(0)->textContent;
$home = $xpath->query('//phone_numbers/home', $user)->item(0)->textContent;
}
Note that the above code (both parts) require that the format is exactly that. If you have conditionals, you might want to change it to something like this (the firstname conditional only):
$userInfo = $doc->getElementsByTagName( "user" );
$xpath = new DomXpath($doc);
foreach ($userInfo as $user) {
$id = $user->getAttribute('id');
$firstQuery = $xpath->query('//first_name', $user);
if ($firstQuery->length > 0) {
$first = $firstQuery->item(0)->textContent;
} else {
$first = '';
}
}

Categories