tags:

views:

53

answers:

3

I have pasted the example of what I need here : http://pastie.org/1005178

I have a xml file with say the following info

<state>
<info>
<name>hello</name>
<zip>51678</zip>
</info>
<info>
<name>world</name>
<zip>54678</zip>
</info>
</state>

Now I need to create a new xml file which has the following

<state>
<info>
<name>hello</name>
<zip>51678</zip>
<lat>17.89</lat>
<lon>78.90</lon>
</info>
<info>
<name>world</name>
<zip>54678</zip>
<lat>16.89</lat>
<lon>83.45</lon>
</info>
</state>

So, basically I need to add lat and lon nodes to each info element. these lat and lon correspond to the zip code which are stored in a mysql file which contains 3 fields - pin, lat and lon

How do i do this recursively. I have say 1000 info elements in a file

Please give me a sample code because I have already tried using simplexml and read the documentation but doesn't see to understand it properly

+2  A: 

Based on the XML you gave in the question (not the pastebin), here is how you could do it with DOM:

$xml = <<< XML
<state>
    <info>
        <name>hello</name>
        <zip>51678</zip>
    </info>
    <info>
        <name>world</name>
        <zip>54678</zip>
    </info>
</state>
XML;

The code below will load the XML into a DOMDocument instance. Then we call a custom function insertGeo() on it and output the result in a clean formatted way:

$dom = new DOMDocument;
$dom->preserveWhiteSpace = FALSE;
$dom->formatOutput = TRUE;
$dom->loadXML($xml); // use ->load('filename') for files
insertGeo($dom, 51678, 1, 2);
echo $dom->saveXML(); // use ->save('filename') for files

The custom function accepts four params:

  • $dom The DOMDocument instance
  • $zip The info/zip text value to insert the geo data to
  • $lat/$lon latitude and longitude obviously

In code:

function insertGeo($dom, $zip, $lat, $lon) {
    $xpath = new DOMXPath($dom);
    $nodes = $xpath->query(sprintf('//info/zip[text() = "%s"]', $name));
    foreach($nodes as $node) {
        $info = $node->parentNode;
        $info->appendChild($dom->createElement('lat', $lat));
        $info->appendChild($dom->createElement('lon', $lon));
    }
}

What it does is query the DOMDocument with an XPath to find all the zip nodes below an info node with a value of $zip. It will then iterate over the resulting list and fetch the info node. Then it will create and append the lat/lon nodes to it. That's all. If you want query for the Name element instead of Zip, just change the XPath accordingly.

Result:

<?xml version="1.0"?>
<state>
  <info>
    <name>hello</name>
    <zip>51678</zip>
    <lat>1</lat>
    <lon>2</lon>
  </info>
  <info>
    <name>world</name>
    <zip>54678</zip>
  </info>
</state>

What you have to do now is to put all your geo data into an array, so you can foreach over it and pass the values to the insertGeo function.

Gordon
Thank you for the solution. But I could also solve my problem using simple xml.
Avinash Sonee
@Avinash You're welcome. There is multiple ways to solve it. The reason I suggested DOM over SimpleXml is because DOM gives me more control over the XML. Also note that DOM is a W3C API and can be found implemented in many languages. Knowing the interface will make it easy for you to use it in other languages, f.i. JavaScript as well.
Gordon
+1  A: 

I would load up all the geolocation info (I assume that "pin" is the zip code?) in an array, then loop over your <info/> nodes and insert the corresponding <lon/> and <lat/>.

// obviously you create that array by loading the stuff from MySQL
$geo = array(
    51678 => array('lat' => 17.89, 'lon' => 78.90),
    54678 => array('lat' => 16.89, 'lon' => 83.45)
);

$state = simplexml_load_file('state.xml');

foreach ($state->info as $info)
{
    $zip = (string) $info->zip;
    $info->lat = $geo[$zip]['lat'];
    $info->lon = $geo[$zip]['lon'];
}

// save to the same file, or another if you want
$state->asXML('result.xml');
Josh Davis
Thanks. This also solves the problem
Avinash Sonee
A: 

Here is the PHP Script which I used to edit my xml:

<?php
//Contact Code Author : [email protected]
//DB Connection Parameters
$dbHost = 'localhost'; // usually localhost
$dbUsername = 'root';
$dbPassword = '';
$dbDatabase = 'demo';
//DB Connection Start
$db = mysql_connect($dbHost, $dbUsername, $dbPassword) or die ("Unable to connect to Database Server.");
mysql_select_db ($dbDatabase, $db) or die ("Could not select database.");

//Since we're already using PHP5, why don't we exploit their easy to use file_get_contents() command?
$xmlFileData = file_get_contents("demo.xml");
//Here's our Simple XML parser!
$xmlData = new SimpleXMLElement($xmlFileData);
//And here's the output.

foreach ($xmlData->Info as $City)
        {
         foreach($City->zip as $izip)
             {
            $sql = "SELECT lat,lon FROM ascii WHERE zip LIKE '$izip'";
            $result = mysql_query($sql);
            $row = mysql_fetch_array($result);
            echo $izip, ", ", $row[0],", ", $row[1],"<br/>";
            $book->addChild('lat',$row[0]);
            $book->addChild('lon',$row[1]);
             }
        }
  echo $xmlData->asXML();
  $xmlData->asXML('updated_demo.xml');
?>

It was very simple and easy this way at least for my problem.

Thanks.

Avinash Sonee