PHP CSV to XML how to deal with pipe delimited strings - php

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

Related

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

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;
}
}
}

Google Script to replace IMPORTXML(too big xml to import with IMPORTXML)

I want to import a Google Shopping XML to a Google Spreadsheet, but Google Spreadsheet shows a error:
Error
Resource at url contents exceeded maximum size.
I need to import the data (and update it each 6 hours) and I don't know how with this error.
A example of what I using is this:
=IMPORTXML("http://avambu.xtechcommerce.com/datafeeds/google_shopping","//channel/item")
But with a larger XML.
There is a script or another solution for this?
Thanks!
The best solution I found for now is with a PHP script.
$filexml = 'GoogleProductFeed.xml';
$xml = simplexml_load_file($filexml);
$xml->registerXPathNamespace('g', 'http://base.google.com/ns/1.0');
if (file_exists($filexml)) {
$xml = simplexml_load_file($filexml);
$i = 1; // Position counter
$values = []; // PHP array
// Writing column headers
$columns = array('title', 'link', 'description', 'g:availability', 'g:price', 'g:image_link', 'g:product_type',
'g:google_product_category', 'g:condition', 'g:identifier_exists', 'g:id');
$fs = fopen('GoogleProductFeed.csv', 'w');
fputcsv($fs, $columns);
fclose($fs);
// Iterate through each <item> node
$node = $xml->xpath('//item');
foreach ($node as $n) {
// Iterate through each child of <item> node
foreach ($columns as $col) {
$values[] = trim($xml->xpath('//item['.$i.']/'.$col)[0]);
}
// Write to CSV files (appending to column headers)
$fs = fopen('GoogleProductFeed.csv', 'a');
fputcsv($fs, $values);
fclose($fs);
$values = []; // Clean out array for next <item> (i.e., row)
$i++; // Move to next <item> (i.e., node position)
}
}
Thanks for #Parfait for the answer of another question with a better PHP script to do this.
To the script run automatically, I need to use the CRON from a linux server.
I would recommend using UrlFetchApp.fetch(); but please be aware that it is also limited to file size of 50MB. Please find my Google App Script code example below.
// Import .xml
var url = "URL of .xml";
// Fect .xml
var xml = UrlFetchApp.fetch(url).getContentText();
// Parse .xml
var document = XmlService.parse(xml);
// Get root
var root = document.getRootElement();
// NameSpaces
var atom = XmlService.getNamespace('http://www.w3.org/2005/Atom');
var base = XmlService.getNamespace('http://base.google.com/ns/1.0');
// Get all children (change "entry" and NameSpace to suitable fit)
var entries = root.getChildren('entry', atom);
Reference
https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app

SimpleXML to CSV with missing tags

So I have an XML file that looks similar to this:
<container>
<example1>some text</example1>
<example2>some text</example2>
<example3>some text</example3>
<example4>some text</example4>
</container>
<container>
<example1>some text</example1>
<example2>some text</example2>
<example4>some text</example4>
</container>
Basically, if example3 doesn't contain any information, the XML author decided to leave it out completely. The trouble is, when I am using my script to convert to CSV, this particular XML file doesn't convert to CSV properly due to the text in the second example4 being displayed under the header of example3 in the CSV file.
This is the PHP script I have to normally works with other XML files.
$file='input.xml';
if (file_exists($file)) {
$xml = simplexml_load_file($file);
$f = fopen('output.csv', 'w');
// array to hold the field names
$headers = array();
// loop through the first set of fields to get names
foreach ($xml->container->children() as $field) {
// put the field name into array
$headers[] = $field->getName();
}
// print headers to CSV
fputcsv($f, $headers, ',', '"');
foreach ($xml->container as $information) {
fputcsv($f, get_object_vars($information), ',', '"');
}
fclose($f);
}
I can't figure out how to predefine the headers that I need and insert the correct information in the correct columns in the CSV.
Any pointers much appreciated.
thanks
mike
If your first entry always present all fields, then its enougth to iterate over the header fields for each line and look if the current line has all entrys.
foreach ($xml->container as $information) {
$vars = get_object_vars($information);
$line = array();
foreach($headers as $field) {
$line[] = isset($vars[$field]) ? $vars[$field] : '';
}
fputcsv($f, $line, ',', '"');
}

Large XML file Parsing Chunk data Filetering in PHP

I have a large XML file more than 100 MB. I am reading the file in chunks like this
$fp = fopen('large.xml', 'r');
while ($data = fread($fp, 4096)) {
The format of XML is like this
<PersonalInfo>
<UserDetail>
<FirstName>ABC</FirstName>
<Occupation>Student</Occupation>
<DateOfBirth>08/14/1999</DateOfBirth>
</UserDetail>
<CaseDetail>....</CaseDetail>
<TransactionDetail>....</TransactionDetail>
</PersonalInfo>
<PersonalInfo>
<UserDetail>
<FirstName>XYZ</FirstName>
<Occupation>Student</Occupation>
<DateOfBirth>04/25/1991</DateOfBirth>
</UserDetail>
<CaseDetail>....</CaseDetail>
<TransactionDetail>.....</TransactionDetail>
</PersonalInfo>
<PersonalInfo>
<UserDetail>
<FirstName>DEF</FirstName>
<Occupation>Teacher</Occupation>
<DateOfBirth>05/12/1984</DateOfBirth>
</UserDetail>
<CaseDetail>....</CaseDetail>
<TransactionDetail>...</TransactionDetail>
</PersonalInfo>
I want to just include those records where the Occupation TAG is "Student" and write those results to a CSV file.
I have tried the preg_match as
preg_match( "/\(.*?)\</PersonalInfo>/s", $data, $match );
to select the Tags and then look into $match but it is returning double values(repetition).
First check if your xml is valid with the help of following link :
http://www.xmlformatter.net/
If your xml is valid then do following :
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
#$dom->load('large.xml');
$tags = $dom->getElementsByTagName('PersonalInfo');
foreach ($tags as $destination) {
foreach($destination->childNodes as $child) {
if ($child->textContent == "Student") {
echo "Write code to create csv file";
}
}
}

Adding data from php/mysql query into an XML file

I want to add/display data from querying from the database and add it into an XML file.
Example, I have a table_persons which has a name and age. I create a mysql query to get its name and age. Then simply put the data(name and age of persons) into an XML file.
How would you do that? Or is it possible?
I suggest you use DomDocument and file_put_contents to create your XML file.
Something like this:
// Create XML document
$doc = new DomDocument('1.0', 'UTF-8');
// Create root node
$root = $doc->createElement('persons');
$root = $doc->appendChild($root);
while ($row = mysql_fetch_assoc($result)) {
// add node for each row
$node = $doc->createElement('person');
$node = $root->appendChild($node);
foreach ($row as $column => $value) {
$columnElement = $doc->createElement($column);
$columnElement = $node->appendChild($columnElement);
$columnValue = $doc->createTextNode($value);
$columnValue = $columnElement->appendChild($columnValue);
}
}
// Complete XML document
$doc->formatOutput = true;
$xmlContent = $doc->saveXML();
// Save to file
file_put_contents('persons.xml', $xmlContent);
<?php
[snip] //database code here
$f = fopen('myxml.xml', 'a+');
foreach($row = mysqli_fetch_assoc($resultFromQuery))
{
$str = "<person>
<name>{$row['name']}</name>
<age>{$row['age']}</age>
</person>\n";
fwrite($f, $str);
}
fclose($f);
?>
Assuming you use mysqli, this code works. If not, suit to fit. In the fopen function call, the a+ tells it to open it for reading at writing, placing the pointer at the end of the file.
Best of luck.

Categories