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.
Related
Maybe its a question answered before but im so noobie in Web Development.
Im trying to get a full XML text from this page:
Human Genome
And, I need to do some XPath queries in that code, like "get the ID" and others.
For example:
//eSearchResult/IdList/Id/node()
How I can to get the full XML in a php object to request data throught XPath queries?
I used this code before:
<?php
$text = $_REQUEST['text'];
$xmlId = simplexml_load_file('https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=gene&term='.$text.'%5bGene%20Name%5d+AND+%22Homo%20sapiens%22%5bOrganism');
$id = $xmlId->IdList[0]->Id;
$xmlGeneralData = simplexml_load_file('https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=gene&id='.$id.'&retmode=xml');
$geneName = $xmlGeneralData->DocumentSummarySet->DocumentSummary[0]->Name;
$geneDesc = $xmlGeneralData->DocumentSummarySet->DocumentSummary[0]->Description;
$geneChromosome = $xmlGeneralData->DocumentSummarySet->DocumentSummary[0]->Chromosome;
echo "Id: ".$id."\n";
echo "Name: ".$geneName."\n";
echo "Description: ".$geneDesc."\n";
echo "Chromosome: ".$geneChromosome."\n";?>
But, according with the profesor, this code doesn't use Xpath queries and is required that the page use it.
Someone can help me or explain me how to do it?
Here's converted code to Xpath query.
<?php
$text = $_REQUEST['text'];
$xmlId = 'https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=gene&term='.$text.'%5bGene%20Name%5d+AND+%22Homo%20sapiens%22%5bOrganism';
//Load XML and define Xpath
$xml_id = new DOMDocument();
$xml_id->load($xmlId);
$xpath = new DOMXPath($xml_id);
//Xpath query to get ID
$elements = $xpath->query("//eSearchResult/IdList/Id");
//Loop through result of xpath query and store in array of ID
if ($elements->length >0) {
foreach ($elements as $entry) {
$id[] = $entry->nodeValue;
}
}
echo "Id: ".$id[0]."\n";
//Output the first string of ID array from xpath result set
$xmlGeneralData = 'https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=gene&id='.$id[0].'&retmode=xml';
//Load XML and define Xpath
$xml_gd = new DOMDocument();
$xml_gd->load($xmlGeneralData);
$xpath = new DOMXPath($xml_gd);
//Xpath query to search for Document Summary with first string of ID array from previous result set
$elements = $xpath->query("//eSummaryResult/DocumentSummarySet/DocumentSummary[#uid='".$id[0]."']");
//Loop through result of xpath query and find nodes and print out the result
if ($elements->length >0) {
foreach ($elements as $entry) {
echo "Name: ".$entry->getElementsByTagName('Name')->item(0)->nodeValue."\n";
echo "Description: ".$entry->getElementsByTagName('Description')->item(0)->nodeValue."\n";
echo "Chromosome: ".$entry->getElementsByTagName('Chromosome')->item(0)->nodeValue."\n";
}
}
?>
Here is where I set up basic variables, such as creating the new DomDoc and such as well as loading some of the Tags. This all works fine at the moment.
<?php
if (isset($_GET['edit'])&& $_GET['edit']=='delete' && isset($_GET['id'])&&!empty($_GET['id'])){
$dom = new DomDocument();
$dom->preserveWhiteSpace = false;
$dom->load("data.xml");
$root = $dom->documentElement;
$record = $root->getElementsByTagName("data");
$ID=$root->getElementsByTagName("ID");
$nodetoremove = null;
//$namenode=$root->getElementsByTagName("own_name");
//$name="";
//$datenode=$root->getElementsByTagName("sign_in");
//$date="";
$newid=$_GET['id'];
foreach($ID as $node){
$pid =$node->textContent;
Here I am checking if it's a new ID and if it is it does the following as seen.
if ($pid == $newid)
{
$nodetoremove=$node->parentNode;
}
}
The issue is here. I am able to go through the selected node I wish to delete ($nodetoremove) and select a specific element (sign_in) but I am unsure how to so. Right now all I can do is go through and print all of the elements within the nodes of $nodetoremove. Is there a way I can get the element I want from XML this way?
//Prints all information within $nodetoremove
foreach ($nodetoremove->childNodes AS $item){
print $item->nodeName . "=" . $item->nodeValue . "<br>";
}
foreach ($nodetoremove as $node) {
}
//Sets $name to the first Child of $nodetoremove
$name=$nodetoremove->firstChild->nodeValue;
//Checks if the nods to remove is not null, if it is removes $nodetoremove
if($nodetoremove!=null){
$root->removeChild($nodetoremove);
?>
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.
I have a script that grabs an xml of my database generated by php and I would like to shuffle the rows before the php script echos the xml so that each time i access the database xml file, I'll receive the database in a different order.
here's part of my php script that outputs the xml:
$dom = new DOMDocument("1.0");
$node = $dom->createElement("database");
$parnode = $dom->appendChild($node);
$query = "SELECT * FROM database WHERE 1";
$result = mysql_query($query);
header("Content-type: text/xml");
while ($row = #mysql_fetch_assoc($result)){
// ADD TO XML DOCUMENT NODE
$node = dom->createElement("data");
$newnode = $parnode->appendChild($node);
$newnode->setAttribute("id", $row['id']);
$newnode->setAttribute("name", $row['name']);
$newnode->setAttribute("date", $row['date']);
$newnode->setAttribute("latitude", $row['latitude']);
$newnode->setattribute("longitude", $row['longitude']);
}
This is where I'd like to randomize the xml output if possible. This seems like the most logical place, but if there's a better place, that's fine with me.
echo $dom->saveXML();
Here's a sample of my xml:
<database>
<data id="1" name="blah" date="2012-10-10" latitude="0" longitude="0"/>
<data id="3" name="blah" date="2012-10-10" latitude="0" longitude="0"/>
<data id="4" name="blah" date="2012-10-10" latitude="0" longitude="0"/>
</database>
Simply put, I would like the xml rows to be in a different order each time i access it. Thanks for your help.
One way around this problem is to use a temporary array to store the rows fetched from DB, then shuffle this array, then walk through it:
$records = array();
while ($row = #mysql_fetch_assoc($result)){
$records[] = $row;
}
shuffle($records);
foreach ($records as $row) {
$node = dom->createElement("data");
$newnode = $parnode->appendChild($node);
$newnode->setAttribute("id", $row['id']);
...
}
The other way is use the original array as it is, but randomize the insertion process instead:
$prevnode = null;
while ($row = #mysql_fetch_assoc($result)){
$node = dom->createElement("data");
if ($prevnode && rand(0, 1) === 0) {
$newnode = $prevnode->insertBefore($node);
} else {
$newnode = $parnode->appendChild($node);
}
$prevnode = $newnode;
$newnode->setAttribute("id", $row['id']);
...
}
If your result set is not very large and your database supports it, you can have the database shuffle the results for you. For example, MySQL can do this:
SELECT * FROM database ORDER BY rand();
Your database may differ.
You could also separate XML generation from result collection. Shuffle the intermediate array:
function get_database_results($dbconn=null) {
$rows = false;
$query = 'SELECT * FROM database';
$res = mysql_query($query, $dbconn);
if ($res) {
$rows = array();
while ($row = mysql_fetch_assoc($res)) {
$rows[] = $row;
}
}
return $rows;
}
function array_to_sxe($rows) {
$sxe = simplexml_load_string('<database></database>');
foreach ($rows as $row) {
$data = $sxe->addChild('data');
foreach ($row as $key => $value) {
$data->addAttribute($key, $value);
}
}
return $sxe;
}
$rows = get_database_results();
shuffle($rows);
$sxe = array_to_sxe($rows);
header('Content-Type: application/xml'); // NOT text/xml!
echo $sxe->asXML();
I will now rant about encodings.
You have to be more careful about your encodings! As it is, you can very easily generate malformed XML.
text/xml means that the xml is in 7-bit ascii. That is very unlikely what you meant.
application/xml means that the xml is utf-8. This is what DOMDocument and SimpleXML output by default, and only accept utf-8 values for methods like setAttribute! This means you need to be absolutely sure:
That the strings you put into the database are utf-8.
That the connection between php and the database is utf-8. (Using SET NAMES utf8 or the charset parameter to the DSN with PDO--which you should be using instead of mysql_*)
That the strings you pull out of the database are utf-8, or at least are converted to utf-8 before use.
You can add
ORDER BY rand()
to your SQL-Query
I'm having difficulty extracting a single node value from a nodelist.
My code takes an xml file which holds several fields, some containing text, file paths and full image names with extensions.
I run an expath query over it, looking for the node item with a certain id. It then stores the matched node item and saves it as $oldnode
Now my problem is trying to extract a value from that $oldnode. I have tried to var_dump($oldnode) and print_r($oldnode) but it returns the following: "object(DOMElement)#8 (0) { } "
Im guessing the $oldnode variable is an object, but how do I access it?
I am able to echo out the whole node list by using: echo $oldnode->nodeValue;
This displays all the nodes in the list.
Here is the code which handles the xml file. line 6 is the line in question...
$xpathexp = "//item[#id=". $updateID ."]";
$xpath = new DOMXpath($xml);
$nodelist = $xpath->query($xpathexp);
if((is_null($nodelist)) || (! is_numeric($nodelist))) {
$oldnode = $nodelist->item(0);
echo $oldnode->nodeValue;
//$imgUpload = strchr($oldnode->nodeValue, ' ');
//$imgUpload = strrchr($imgUpload, '/');
//explode('/',$imgUpload);
//$imgUpload = trim($imgUpload);
$newItem = new DomDocument;
$item_node = $newItem ->createElement('item');
//Create attribute on the node as well
$item_node ->setAttribute("id", $updateID);
$largeImageText = $newItem->createElement('largeImgText');
$largeImageText->appendChild( $newItem->createCDATASection($largeImgText));
$item_node->appendChild($largeImageText);
$urlANode = $newItem->createElement('urlA');
$urlANode->appendChild( $newItem->createCDATASection($urlA));
$item_node->appendChild($urlANode);
$largeImg = $newItem->createElement('largeImg');
$largeImg->appendChild( $newItem->createCDATASection($imgUpload));
$item_node->appendChild($largeImg);
$thumbnailTextNode = $newItem->createElement('thumbnailText');
$thumbnailTextNode->appendChild( $newItem->createCDATASection($thumbnailText));
$item_node->appendChild($thumbnailTextNode);
$urlB = $newItem->createElement('urlB');
$urlB->appendChild( $newItem->createCDATASection($urlA));
$item_node->appendChild($urlB);
$thumbnailImg = $newItem->createElement('thumbnailImg');
$thumbnailImg->appendChild( $newItem->createCDATASection(basename($_FILES['thumbnailImg']['name'])));
$item_node->appendChild($thumbnailImg);
$newItem->appendChild($item_node);
$newnode = $xml->importNode($newItem->documentElement, true);
// Replace
$oldnode->parentNode->replaceChild($newnode, $oldnode);
// Display
$xml->save($xmlFileData);
//header('Location: index.php?a=112&id=5');
Any help would be great.
Thanks
Wasn't it supposed to be echo $oldnode->firstChild->nodeValue;? I remember this because technically you need the value from the text node.. but I might be mistaken, it's been a while. You could give it a try?
After our discussion in the comments on this answer, I came up with this solution. I'm not sure if it can be done cleaner, perhaps. But it should work.
$nodelist = $xpath->query($xpathexp);
if((is_null($nodelist)) || (! is_numeric($nodelist))) {
$oldnode = $nodelist->item(0);
$largeImg = null;
$thumbnailImg = null;
foreach( $oldnode->childNodes as $node ) {
if( $node->nodeName == "largeImg" ) {
$largeImg = $node->nodeValue;
} else if( $node->nodeName == "thumbnailImg" ) {
$thumbnailImg = $node->nodeValue;
}
}
var_dump($largeImg);
var_dump($thumbnailImg);
}
You could also use getElementsByTagName on the $oldnode, then see if it found anything (and if a node was found, $oldnode->getElementsByTagName("thumbnailImg")->item(0)->nodeValue). Which might be cleaner then looping through them.