PHP mysql - Generating a sitemaps without exceeding 50k rows limit - php

I have the follwing PHP / MYSQL sitemap that generates a sitemap into the browser. How can i make it save itself to a file and split on 50.000 ? i cant get it to work properly as the script just outputs into plain text. I want the script to output into a file
currently
<?
$xmlfile = 'sitemap.xml';
// this variable will contain the XML sitemap that will be saved in $xmlfile
$xmlsitemap = '<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
// Connection data (server_address, name, password, database_name)
$hostdb = '';
$userdb = '';
$passdb = '';
$namedb = '';
try {
// Connect and create the PDO object
$conn = new PDO("mysql:host=$hostdb; dbname=$namedb", $userdb, $passdb);
$conn->exec("SET CHARACTER SET utf8"); // Sets encoding UTF-8
// Define and perform the SQL SELECT query
$sql = "SELECT `shortUrl` FROM `shorturl`";
$result = $conn->query($sql);
// If the SQL query is succesfully performed ($result not false)
if($result !== false) {
// Parse the result set, and add the URL in the XML structure
foreach($result as $row) {
$xmlsitemap .= '
<url>
<loc>'. $row['shortUrl'] .'</loc>
<priority>0.5</priority>
<changefreq>weekly</changefreq>
</url>';
}
}
$conn = null; // Disconnect
}
catch(PDOException $e) {
echo $e->getMessage();
}
$xmlsitemap .= '</urlset>';
file_put_contents($xmlfile, $xmlsitemap); // saves the sitemap on server
// outputs the sitemap (delete this instruction if you not want to display the sitemap in browser)
echo $xmlsitemap;
?>

Let's take a look at the code that generating url records..
<url>
<loc>'. $row['shortUrl'] .'</loc>
<priority>0.5</priority>
<changefreq>weekly</changefreq>
</url>';
As above, one record contains 5 rows. So your array must contains max 10.000 records right ?
If we split our array into the chunks which contains max 10.000 records, we can easily save each chunk records in different files.
try {
// connect db and get records
# give attention here
$chunks = array_chunk($result, 10000)
// If the SQL query is succesfully performed ($result not false)
if($result !== false) {
// Parse the result set, and add the URL in the XML structure
foreach ($chunks as $key => $chunk) {
$xmlsitemap .= '</urlset $namespaces>';
foreach ($chunk as $row){
$xmlsitemap .= '
<url>
<loc>' . $row['shortUrl'] . '</loc>
<priority>0.5</priority>
<changefreq>weekly</changefreq>
</url>';
}
$xmlsitemap .= '</urlset>';
file_put_contents("path/to/directory/sitemap-".$key.".xml", $xmlsitemap);
}
}
}
// check errors
Btw don't forget to create sitemap index for those

Welcome to StackOverflow.
Simply run a counter in your foreach and break it to your desired value.
Not tested code is below
if($result !== false) {
// Parse the result set, and add the URL in the XML structure
$counter = 0;
foreach($result as $row) {
$counter++
$xmlsitemap .= '
<url>
<loc>'. $row['shortUrl'] .'</loc>
<priority>0.5</priority>
<changefreq>weekly</changefreq>
</url>';
if($counter==4900){
break;
}
}
}

Related

Differences between two xml strings using php

I'm trying to compare and check the differences between two xml strings but my code is not detecting any changes in xml strings!
for ex my first string contains :
<Result>
<pid>10</pid>
<DocID>29</DocID>
<Response>True</Response>
<DocID>60<DocID>
<Blvd_Name>dfdfdfdfd</Blvd_Name>
<Alley_Name>dfd</Alley_Name>
<Plate_Number>654654</Plate_Number>
<Post_Code>654654654</Post_Code>
<Phone_1>654654</Phone_1>
<Phone_2>654654564</Phone_2>
<Fax>2323232</Fax>
<Website>ewewew</Website>
<Mobile_No>23232323232</Mobile_No>
<Information>
<Info>
<National_Code>106397854</National_Code>
<Start_Activity_Date>2015-12-22 00:00:00</Start_Activity_Date>
<End_Activity_Date>2016-01-03 00:00:00</End_Activity_Date>
</Info>
</Information>
<Service_Times>
<Service_Time>15:30 - 17:45</Service_Time>
</Service_Times>
</Result>
the second string is :
<Result>
<pid>10</pid>
<DocID>29</DocID>
<Response>True</Response>
<DocID>60<DocID>
<Blvd_Name>dfdfdfdfd</Blvd_Name>
<Alley_Name>dfd</Alley_Name>
<Plate_Number>654654</Plate_Number>
<Post_Code>654654654</Post_Code>
<Phone_1>11111</Phone_1>
<Phone_2>6546111154564</Phone_2>
<Fax>11111</Fax>
<Website>11111</Website>
<Mobile_No>11111</Mobile_No>
<Information>
<Info>
<National_Code>106397854</National_Code>
<Start_Activity_Date>2015-12-22 8:01:50</Start_Activity_Date>
<End_Activity_Date>2016-01-03 11:20:10</End_Activity_Date>
</Info>
</Information>
<Service_Times>
<Service_Time>15:30 - 17:45</Service_Time>
</Service_Times>
</Result>
as you can see there are some differences in the values of the objects!
I've tried simplexmlload and then array_diff and jason encode and decode and comparing the jason but there was not chance to detect the differences.
any suggestion how to accomplish that ?
my array diff code :
$result = array_diff($Data1, $Data2);
if(empty($result)){
// the XML documents are the same
$res = "No changes";
} else {
// they are different
$res = "There are Some changes";
}
You can leave the data as raw text ane see the difference by using the following
<?php
$difference = xdiff_string_diff($Data1, $Data2);
Ok I solved the problem using simple if comparison method and it worked.
I first opened two xml files and then i copared them using method below, if i change a value/structure in second xml file it gives me "there are some changes".
$file = './Result.xml';
if (file_exists($file)) {
$Data = file_get_contents($file);
} else {
exit('Failed to open ' . $file);
}
$file2 = './Result2.xml';
if (file_exists($file2)) {
$Data2 = file_get_contents($file2);
} else {
exit('Failed to open ' . $file2);
}
if ($Data === $Data2) {
// the XML documents are the same
$res = "No changes";
} else {
// they are different: print the reason why
$res = "There are Some changes";
}

PHP CSV to XML how to deal with pipe delimited strings

Firstly I know this a rather long/detailed post if you are looking for the gist of my problem you can jump to the bottom where I have a TLDR. Thanks in advance to all commenters
I have been working on a feature for my clients website. They have an older version of Microsoft Excel on MAC which does not support .XML - the store system they have uses .XML
So I need to code the ability to convert CSV into XML, but the XML must conform to the structure required by the store component. I have already coded an XML to CSV function which does work.
This is the XML output by the store system (I have removed the values for security of my client's customers):
<orders>
<order>
<order_id>38</order_id>
<order_number>000015</order_number>
<order_status>Authorized</order_status>
<order_date>0000-00-00 00:00:00</order_date>
<customer_email>test#someemail.ca</customer_email>
<order_amount>order total</order_amount>
<base_order_amount>pre shipping order total</base_order_amount>
<shipping_type>Basic Shipping</shipping_type>
<shipping_price> $0.00</shipping_price>
<billing_first_name>Name</billing_first_name>
<billing_last_name>B</billing_last_name>
<billing_address1>PO / Add</billing_address1>
<billing_address2></billing_address2>
<billing_city>Town</billing_city>
<billing_state_province>province</billing_state_province>
<billing_country>Canada</billing_country>
<billing_postal_code>postal code</billing_postal_code>
<billing_phone></billing_phone>
<emt_quest>test</emt_quest>
<emt_answ>test</emt_answ>
<emt_answ_conf>test</emt_answ_conf>
<shipping_first_name>Name</shipping_first_name>
<shipping_last_name>B</shipping_last_name>
<shipping_address1>PO / Add</shipping_address1>
<shipping_address2></shipping_address2>
<shipping_city>Town</shipping_city>
<shipping_state_province>province</shipping_state_province>
<shipping_country>Canada</shipping_country>
<shipping_postal_code>postal code</shipping_postal_code>
<shipping_phone></shipping_phone>
<items>
<item>
<item_name>Sample Item</item_name>
<item_price>$8.00</item_price>
<item_quantity>12</item_quantity>
</item>
<item>
<item_name>Sample Item 2</item_name>
<item_price>$12.00</item_price>
<item_quantity>12</item_quantity>
</item>
</items>
</order>
This is the code of my XML to CSV function
<?php
function xml2csv($xmlFile, $xPath) {
$csvData = "";
// Load the XML file
$xml = simplexml_load_file($xmlFile);
// xpath to search
$path = $xml->order;
//get headers (xpath must match above)
$headers = get_object_vars($xml->order[0]);
// Loop through the first row to get headers
foreach($headers as $key => $value){
$csvData .= $key . ',';
}
// Trim off the extra comma
$csvData = trim($csvData, ',');
// Add an LF
$csvData .= "\n";
foreach($path as $item) {
// Loop through the elements in specificed xpath
foreach($item as $key => $value) {
//check for a second generation children of specified first generation child
if ($key == "items") {
$itemString = "";
// if first generation child has children then loop through each second gen child
foreach ($item->children() as $child) {
// loop through each xpath of second generation child
foreach($child as $value) {
// for value of each xpath of second generation child get value as out
foreach($value->children() as $out) {
//combine each value into itemString for export to .csv
$itemString .= $out . "|";
}
}
}
// place item string in csvData string and remove extra pipe
$csvData .= trim($itemString, "|");
}
//else put xpath values of first geneartion child in .csv
else {
$csvData .= trim($value) . ',';
}
}
// Trim off the extra comma
$csvData = trim($csvData, ',');
// Add an LF
$csvData .= "\n";
}
// Return the CSV data
return $csvData;
}
When called with a given .XML file from the store system it outputs the following .CSV file (I have used dummy values the 'item price' is not accidental)
order_id,order_number,order_status,order_date,customer_email,order_amount,base_order_amount,shipping_type,shipping_price,billing_first_name,billing_last_name,billing_address1,billing_address2,billing_city,billing_state_province,billing_country,billing_postal_code,billing_phone,emt_quest,emt_answ,emt_answ_conf,medicinal_use,shipping_first_name,shipping_last_name,shipping_address1,shipping_address2,shipping_city,shipping_state_province,shipping_country,shipping_postal_code,shipping_phone,items
00,000000,Authorized,0000-00-00 00:00:00,i#me.ca,$00.00,$00.00,Basic Shipping,$0.00,Me,Initial,123 Some Person Street,,Personville,Prov/State,Country,postal,,test,test,test,test,test,test,test,,test,test,test,test,,item name|item price|item quantity
01,000000,Authorized,0000-00-00 00:00:00,i#me.ca,$00.00,$00.00,Basic Shipping,$0.00,Me,Initial,123 Some Person Street,,Personville,Prov/State,Country,postal,,test,test,test,test,test,test,test,,test,test,test,test,,item name|item price|item quantity
02,000000,Authorized,0000-00-00 00:00:00,i#me.ca,$00.00,$00.00,Basic Shipping,$0.00,Me,Initial,123 Some Person Street,,Personville,Prov/State,Country,postal,,test,test,test,test,test,test,test,,test,test,test,test,,item name|item price|item quantity
03,000000,Authorized,0000-00-00 00:00:00,i#me.ca,$00.00,$00.00,Basic Shipping,$0.00,Me,Initial,123 Some Person Street,,Personville,Prov/State,Country,postal,,test,test,test,test,test,test,test,,test,test,test,test,,item name|item price|item quantity
04,000000,Authorized,0000-00-00 00:00:00,i#me.ca,$00.00,$00.00,Basic Shipping,$0.00,Me,Initial,123 Some Person Street,,Personville,Prov/State,Country,postal,,test,test,test,test,test,test,test,,test,test,test,test,,item name|item price|item quantity|item name|item price|item quantity
The purpose here is that my client can download a .CSV directly from the store system (rather than its default .XML) - deal with it in excel as they need to process their orders, and then upload that .CSV back into the store - where it will automatically convert to XML formed like I have shown above.
Since .CSV is a flat format what I did was condense the items XML into a simple .CSV string where each value is delimited by a | which will not be used in any of our markup text on the site. As such item name|item price|item quantity
Here is my code which attempts to achieve this, I come close but I am having some wonky behaviour with the output. It throws an undefined offet error on the noted line $itemvalue = $doc->createTextNode($irow[$g]); (as if the loop is running too many times) and also does not produce the expected output.
function contains($substring, $string) {
$pos = strpos($string, $substring);
if($pos === false) {
// string needle NOT found in haystack
return false;
}
else {
// string needle found in haystack
return true;
}
}
function csv2xml($csvData) {
$outputFilename = 'test.xml';
// Open csv to read
$input = fopen($csvData, 'rt');
// Get the headers of the file
$headers = fgetcsv($input);
// Create a new dom document with pretty formatting
$doc = new DomDocument();
$doc->formatOutput = true;
// Add a root node to the document
$root = $doc->createElement('orders');
$root = $doc->appendChild($root);
while (($row = fgetcsv($input)) !== FALSE) {
$container = $doc->createElement('order');
foreach ($headers as $i => $header)
{
//set temp file name here
$tempFile = "temp.csv";
//prepare mockCSV
$mockCSV = "";
$mockCSV .= "item_name,item_price,item_quantity";
$mockCSV .= "\n";
//check if current property has items data with |
if (contains("|", $row[$i])) {
//if it does create array of data
$item_arr = explode("|", $row[$i]);
//create header for 'items' node
$child = $doc->createElement($header);
$child = $container->appendChild($child);
//count for items
$count = 0;
foreach($item_arr as $k => $item) {
$mockCSV .= trim($item) . ",";
if($count == 2) {
// Trim off the extra comma
$mockCSV = trim($mockCSV, ',');
// Add an LF
$mockCSV .= "\n";
}
$count++;
}
// Trim off the extra comma
$mockCSV = trim($mockCSV, ',');
// Add an LF
$mockCSV .= "\n";
//put mock CSV data in temp file
$f = fopen($tempFile, "w");
fwrite($f, $mockCSV);
fclose($f);
//get data from temp file
$iteminput = fopen($tempFile, 'rt');
//get headers from temp file
$itemheaders = fgetcsv($iteminput);
while (($irow = fgetcsv($iteminput)) !== FALSE) {
$itemchild = $doc->createElement('item');
foreach($itemheaders as $g => $itemheader) {
$subchild = $doc->createElement($itemheader);
$subchild = $itemchild->appendChild($subchild);
$itemvalue = $doc->createTextNode($irow[$g]); /* OFFSET HAPPENS HERE */
$itemvalue = $subchild->appendChild($itemvalue);
}
}
$itemchild = $child->appendChild($itemchild);
}
else {
$child = $doc->createElement($header);
$child = $container->appendChild($child);
$value = $doc->createTextNode($row[$i]);
$value = $child->appendChild($value);
}
}
$root->appendChild($container);
}
$strxml = $doc->saveXML();
$handle = fopen($outputFilename, "w");
fwrite($handle, $strxml);
fclose($handle);
}
echo csv2xml("test.csv");
?>
The expected output should be the same as the XML structure I posted above, but instead it is doing this:
<orders>
<order>
<order_id>38</order_id>
<order_number>000015</order_number>
<order_status>Authorized</order_status>
<order_date>0000-00-00 00:00:00</order_date>
<customer_email>test#someemail.ca</customer_email>
<order_amount>$96.00</order_amount>
<base_order_amount>$96.00</base_order_amount>
<shipping_type>Basic Shipping</shipping_type>
<shipping_price> $0.00</shipping_price>
<billing_first_name>Name</billing_first_name>
<billing_last_name>B</billing_last_name>
<billing_address1>PO / Add</billing_address1>
<billing_address2></billing_address2>
<billing_city>Town</billing_city>
<billing_state_province>province</billing_state_province>
<billing_country>Canada</billing_country>
<billing_postal_code>postal code</billing_postal_code>
<billing_phone></billing_phone>
<emt_quest>test</emt_quest>
<emt_answ>test</emt_answ>
<emt_answ_conf>test</emt_answ_conf>
<shipping_first_name>Name</shipping_first_name>
<shipping_last_name>B</shipping_last_name>
<shipping_address1>PO / Add</shipping_address1>
<shipping_address2></shipping_address2>
<shipping_city>Town</shipping_city>
<shipping_state_province>province</shipping_state_province>
<shipping_country>Canada</shipping_country>
<shipping_postal_code>postal code</shipping_postal_code>
<shipping_phone></shipping_phone>
<items>
<item>
<item_name></item_name>
<item_price></item_price>
<item_quantity></item_quantity>
</item>
</items>
</order>
And not putting the values in for some of the fields. Also it does not repeat for double product entries as shown whose source .CSV field looks like this item name|item price|item quantity|item name|item price|item quantity
This is my problem, I can't seem to handle the pipe delimited field properly it doesn't output as expected. In an earlier version of the code I got all the data, but it did not create separate 'item' nodes.
Any help is much appreciated, at this point I think its something simple and I just need another pair of eyes on the subject.
More to the point I am using very patchy code here I feel, I am out of practice with .PHP - I feel there must be some sort of logic problem with how I am going about this - my way can work but there must be a more streamlined method. If anyone could tell me what that is - that's the answer I'm really looking for.
TL:DR starts here
I am trying to convert .CSV data into structured .XML data using pipe delimiting for the second generation and third generation XML children
Only one field in my source .CSV file 'items' contains such information - all other items are single key single entry the data looks like this item name|item price|item quantity|item name|item price|item quantity
So what I do is check for | inside of the .CSV string which is currently being ran through the loop and if it is detected, I use explode() to create an array of what was in there.
I've tried recreating a mock CSV file and putting it in a temp directory to place this information in and then using basic CSV to XML which does work in my program to place that data into the XML Dom Document
Expected output:
<items>
<item>
<item_name>Sample Item</item_name>
<item_price>$8.00</item_price>
<item_quantity>12</item_quantity>
</item>
<item>
<item_name>Sample Item 2</item_name>
<item_price>$8.00</item_price>
<item_quantity>12</item_quantity>
</item>
</items>
Output I am getting:
<items>
<item>
<item_name></item_name>
<item_price></item_price>
<item_quantity></item_quantity>
</item>
</items>
A lot of info I need to get out there to properly illustrate the issue but my problem is simple - how can I achieve the output I want.
Let me backup and offer a routine for CSV to XML first, then take care of the piped elements.
Some comments:
I prefer SimpleXML over DOM for its ease of use, so I'll use it in the example. Of course, it can be done with DOM as well.
I'll make use of str_getcsv() instead of fgetcsv() to be able to create a working example online.
basic CSV to XML
// XML: set up object
$xml = simplexml_load_string("<orders/>");
// CSV: assume CSV in $c, get it as a whole
$csv = str_getcsv($c, "\n");
// CSV: separate 1st row with field names from the following rows
$names = str_getcsv(array_shift($csv));
// CSV: parse row by row
foreach ($csv as $row) {
// CSV: combine names as keys => data as values
$row = array_combine($names, str_getcsv($row));
// XML: create new <order>
$xml_order = $xml->addChild("order");
// CSV: parse a single row
foreach ($row as $key => $value) {
// *****
// XML: create field as child of <order>
$xml_order->addChild($key, $value);
// *****
}
}
handle piped elements
the following code replaces the lines between // ***** above
// CSV: check for pipes, attention use strict comparison ===
if (strpos($value, "|") === false) {
// XML: no pipe, create node as a child of <order>
$xml_order->addChild($key, $value);
} else {
// CSV: pipe present, split up data
$csv_items = str_getcsv($value,"|");
// XML: create <items> node
$xml_items = $xml_order->addChild($key);
// CSV: iterate over $csv_items, each 3 elements = 1 row
// chop row after row
while (!empty($csv_items)) {
// XML: create <item> node as child of <items>
$xml_item = $xml_items->addChild("item");
// XML: create children of <item> node
$xml_item->addChild("item_name", array_shift($csv_items));
$xml_item->addChild("item_price", array_shift($csv_items));
$xml_item->addChild("item_quantity", array_shift($csv_items));
}
}
combine code without comments
$xml = simplexml_load_string("<orders/>");
$csv = str_getcsv($c, "\n"); // assume CSV in $c
$names = str_getcsv(array_shift($csv));
foreach ($csv as $row) {
$row = array_combine($names, str_getcsv($row));
$xml_order = $xml->addChild("order");
foreach ($row as $key => $value) {
if (strpos($value, "|") === false)
$xml_order->addChild($key, $value);
else {
$csv_items = str_getcsv($value,"|");
$xml_items = $xml_order->addChild($key);
while (!empty($csv_items)) {
$xml_item = $xml_items->addChild("item");
$xml_item->addChild("item_name", array_shift($csv_items));
$xml_item->addChild("item_price", array_shift($csv_items));
$xml_item->addChild("item_quantity", array_shift($csv_items));
}
}
}
}
see it working: https://eval.in/368945

String parsing error while writing an xml file in php

I am writing an sitemap file with php code.I am able to write the file correctly according to requirement.But i want to add namespace tag to starting node of xml file,I tried it doing by the code.But got following error
Uncaught exception Exception with message 'String could not be parsed as XML'
following is my xml structure
<urlset>
<url>
<loc>url1</loc>
</url>
..
..
</urlset>
There are number of url fragments under the parent node as urlset.I want to add namespace tag for sitemaps to urlset node.Thats the only thing i am not able to.Xml file is quite bigger,i am not able to do it manually..
following is my xml formation code
<?php
//Create Database connection
$mysqli = new mysqli('localhost', 'user', 'pass', 'dbname');
if(mysqli_connect_errno()) {
echo "Connection Failed: " . mysqli_connect_errno();
}
/* if (!$mysqli->set_charset("utf8")) {
printf("Error loading character set utf8: %s\n", $mysqli->error);
} else {
printf("Current character set: %s\n", $mysqli->character_set_name());
}
*/
$xml = new SimpleXMLElement('<xml/>');
for ($i = 0; $i < 2; $i++) {
// used to be: $query='select tablecolname1 from tablename limit 10000';
$start = $i * 50000;
$query = "select Siteurl from tablename limit $start, 50000";
$result = mysqli_query($mysqli,$query);
//Create SimpleXMLElement object
$xml = new SimpleXMLElement('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">');
while($row = mysqli_fetch_array($result)) {
$mydata = $xml->addChild('url');
$mydata->loc=$row['Siteurl'];
//htmlentities(strip_tags($mydata->loc=$row['Siteurl']), ENT_COMPAT,'utf-8');
}
// used to be: $fp = fopen("folder/file2.xml","wb");
$fp = fopen("site/sitemap$i.xml","wb");
fwrite($fp,utf8_encode($xml->asXML()));
fclose($fp);
}
$xml = new SimpleXMLElement('<urlset/>');
?>
Please guide me on how to add namespace tag to urlset tag..
SimpleXMLElement expects as parameter "a well-formed XML string" according to the documentation.
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' is not such a string.
You can build a XML from PHP in (at least) two (simple) ways:
either only by echoing the content you want in your XML file (tags included):
header('Content-Type:text/xml');
echo '<?xml version="1.0" encoding="UTF-8"?>';
echo '<urlset xmlns="...">';
...
echo '</urlset>';
or by using the SimpleXML object and building the DOM tree (see example #10 in documentation):
header('Content-Type:text/xml');
$xml=new SImpleXMLElement('<xml/>');
$urlset=$xml->addChild('urlset');
$urlset->addAttribute('xmlns','...');
...
echo $xml->asXML();

PHP while loop to generate a KML file

Given a MySQL table of real estate data, I would like to generate a KML file with the following output:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<Placemark>
<name>Property Address Pulled from Address Field</name>
<description>
Some descriptive data pulled from table inserted here.
</description>
<Point>
<coordinates>Latitude FROM Lat,Long FROM Lng</coordinates>
</Point>
</Placemark>
</Document>
</kml>
This is the code I have so far. As you can see, I am having trouble writting a loop that will structure my KML as shown above. Any help is highly appreciated!
<?php
require("phpsqlgeocode_dbinfo.php");
// Start XML file, create parent node
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true; //This was added from the PHP Doc. Nice output.
// Creates the root KML element and appends it to the root document.
$node = $dom->createElementNS('http://www.opengis.net/kml/2.2', 'kml');
$parNode = $dom->appendChild($node);
// Creates a KML Document element and append it to the KML element.
$dnode = $dom->createElement('Document');
$docNode = $parNode->appendChild($dnode);
// Opens a connection to a mySQL server
$connection=mysql_connect (localhost, $username, $password);
if (!$connection) {
die("Not connected : " . mysql_error());
}
// Set the active mySQL database
$db_selected = mysql_select_db($database, $connection);
if (!$db_selected) {
die ("Can\'t use db : " . mysql_error());
}
// Search the rows in the markers table
$query = sprintf("SELECT * FROM markers");
$result = mysql_query($query);
if (!$result) {
die("Invalid query: " . mysql_error());
}
header("Content-type: application/vnd.google-earth.kml+xml");
// Iterate through the rows, adding KML nodes for each
while ($row = #mysql_fetch_assoc($result)){
$dnode = $dom->createElement("Placemark");
$newnode = $docNode->appendChild($dnode);
$newnode = $newnode->createElement("Name");
$newnode = $newnode->createElement("Description");
$newnode = $newnode->createElement("Coordinates");
}
echo $dom->saveXML() . "\n";
?>
createElement() is a method of the DOMDocument class (the root document $dom) and not of DOMElement, to my knowledge (and based on my reading of the documentation.
You have created 3 new elements, but you have not appended any of them as children of $dnode. Use $dom->createElement() for each and append it to the correct $dnode (Placemark)
// Iterate through the rows, adding KML nodes for each
while ($row = mysql_fetch_assoc($result)){
$dnode = $dom->createElement("Placemark");
$newnode = $docNode->appendChild($dnode);
// Append each $newnode after creating from $dom
// Set its nodeValue to a column from your fetch call
// before appending it to the parent node
// Substitute your correct column names from mysql_fetch_assoc()
$newnode = $dom->createElement("Name");
$newnode->nodeValue = $row['Name'];
$dnode->appendChild($newnode);
$newnode = $dom->createElement("Description");
$newnode->nodeValue = $row['Description'];
$dnode->appendChild($newnode);
//Coordinates are a child node of the 'Point' node
$pointnode = $dom->creteElement("Point");
$dnode-appendChild($pointnode);
$coordsnode = $dom->createElement("Coordinates");
$coordsnode->nodeValue = $row['Coordinates'];
$pointnode->appendChild($coordsnode);
}
echo $dom->saveXML() . "\n";
To force a .kml filename, use a Content-Disposition header:
header("Content-type: application/vnd.google-earth.kml+xml");
header("Content-disposition: inline; filename=$somefilename.kml");

SQL data to XML file

Is it possible to save the below output to an XML file as its currently just displayed in the source?
$host = "localhost"; // host name
$user = "#"; // database user name
$pass = "#"; // database password
$database = "#"; // database name
// connecting to database
$connect = #mysql_connect($host,$user,$pass)or die (#mysql_error());
// selecting database
#mysql_select_db($database,$connect) or die (#mysql_error());
// default header(don't delete)
header("Content-Type: text/xml;charset=iso-8859-1");
echo '<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
// mytable = your content table name
$query = #mysql_query("SELECT * FROM urls");
while($row = #mysql_fetch_array($query)){
// [url] = content url
$url = $row['url'];
// [time] = content date
$date = date("Y-m-d", $row['time']);
// NO CHANGES BELOW
echo
'<url>
<loc>' . $url .'</loc>
<lastmod>'. $date .'</lastmod>
<changefreq>daily</changefreq>
<priority>0.8</priority>
</url>
';
}
echo '</urlset>';
I know I can use .htaccess to make the file be seen as an XML format however I want the data to be saved onto an actual file.
You could try changing each echo to append the line to a string variable, for example:
// Instead of
echo '<?xml version="1.0"?>';
echo '<url>';
// etc.
$xml = '<?xml version="1.0"?>';
$xml .= '<url>';
// and so on
Then use one of the file functions to save to a file. file_put_contents is a simple method:
file_put_contents("/path/to/file.xml", $xml);
A more robust solution, if you want to take this further, could be to use the DOM module to build the XML structure:
$document = new DOMDocument("1.0");
$root = $document->createElement("urlset");
$root->setAttribute("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9");
$document->appendChild($root);
while ($row = mysql_query($query)) {
$item = $document->createElement("url");
$root->append($item);
// etc.
}
echo $document->saveXML();
NOTE: This answer assumes that by "save file" you mean "trigger the Save As dialog in the browser when someone views the page".
text/xml isn't really the correct content-type. You really should at least application/xml for generic XML or the appropriate content type for XML sub-formats such as RSS or docx.
If you want to trigger a file download dialog in the client browser, then you also need to send a content-disposition header that tells the browser that you want it to download the file and give a preferred filename.
There are some issues with your code that need addressing too.
Overuse of # for error suppression. This is a bad idea for a huge variety of reasons. Remove the # operators and handle any generated errors in a more robust way.
Your character encoding heading specifies one character set (latin-1) but your XML preamble specifies a totally different one (UTF-8). That's a recipe for disaster.
Use output buffers
ob_start();
... do everything you actually did before ...
$content = ob_get_contents();
ob_end_clean();
//Write to a file
file_put_contents('filename.xml', $content);
And thats all...
Using fwrite it should be straight forward :
$f = fopen('data.xml', 'w'); //open a file for writing
fwrite($f, $myxmltext); // write some things to it
fclose($f); // close it when finished

Categories