Wrox Programmer Forums
| Search | Today's Posts | Mark Forums Read
Beginning PHP Beginning-level PHP discussions. More advanced coders should post to the Pro PHP forum.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the Beginning PHP section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
  #1 (permalink)  
Old July 16th, 2003, 04:59 AM
Authorized User
 
Join Date: Jun 2003
Location: Kings Lynn, Norfolk, United Kingdom.
Posts: 10
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via ICQ to starsol
Default Chapter 14 XML

I've been through the 'Lord of the Rings' themed example of how to get data from XML files, but I can't figure out how to get individual peices of data from an XML file.

For example, I have a US Dollars to Euros, Pounds, Canadian Dollars and Australian Dollars currency converter on several websites, and instead of having to manually edit the exchange rates in each file, I would prefer to edit just one XML file and have the exchange rates called from that.

The XML file I have created looks like:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE exchange_rates [
  <!ELEMENT currency (name, rate)>
  <!ELEMENT name (#PCDATA)>
  <!ELEMENT rate (#PCDATA)>
]>
<exchange_rates>
 <currency nation="European Union">
  <name>Euro</name>
  <rate>0.890234</rate>
 </currency>
 <currency nation="United Kingdom">
  <name>Pound</name>
  <rate>0.625547</rate>
 </currency>
 <currency nation="Canada">
  <name>Canadian Dollar</name>
  <rate>1.3927</rate>
 </currency>
 <currency nation="Australia">
  <name>Australian Dollar</name>
  <rate>1.53421</rate>
 </currency>
</exchange_rates>

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

and the convertor file currently looks like this:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

<p align="center">
<b>[u]
Currency Converter
</u></b>
</p>

<p align="left">

<?php
if( ! ($fp = fopen("http://www.starsol.co.uk/scripts/files/currency_ex.xml" , " r" )) )
    die("Unable to open XML file.");
$currency_counter = 0;
$currency_data = array();
$xml_current_tag_state ='';

function startElementHandler( $parser, $element_name , $element_attribs )
{
global $currency_counter;
global $currency_data;
global $xml_current_tag_state;

if( $element_name == "CURRENCY" )
{
$currency_data[$currency_counter]["nation"] = $element_attribs["NATION"];
}
else
{
$xml_current_tag_state = $element_name;
}
}

function endElementHandler( $parser, $element_name )
{
global $currency_counter;
global $currency_data;
global $xml_current_tag_state;

$xml_current_tag_state = '';

if( $element_name = "CURRENCY" )
{
$currency_counter++;
}
}
function characterDataHandler( $parser , $data )
{
global $currency_counter;
global $currency_data;
global $xml_current_tag_state;

if( $xml_current_tag_state == '' )
return;
if( $xml_current_tag_state == "NAME" ) {
$currency_data[$currency_counter]["name"] = $data;
}
if( $xml_current_tag_state == "RATE" ) {
$currency_data[$currency_counter]["rate"] = $data;
}
}
if( !($xml_parser = xml_parser_create()) )
die("Couldn't create XML parser.");

xml_set_element_handler($xml_parser, "startElementHandler", "endElementHandler");
xml_set_character_data_handler($xml_parser, "characterDataHandler");

while( $data = fread($fp, 4096) )
{
if( !xml_parse($xml_parser, $data, feof($fp)) )
{
break;
}
}
xml_parser_free($xml_parser);

for( $i=0 ; $i < $currency_counter ; ++$i )
{
echo $currency_data[$i]["name"];
echo $currency_data[$i]["rate"];
echo $currency_data[$i]["nation"];


if ($currency == "Euro"){
$convamount = $amount * $eurorate;
$convamount = round($convamount, 2);
echo"<b>$amount</b> US Dollars is approximately equal to <b>$convamount</b> Euros.";
}
if ($currency == "Pound"){
$convamount = $amount * $poundrate;
$convamount = round($convamount, 2);
echo"<b>$amount</b> US Dollars is approximately equal to <b>$convamount</b> Pounds.";
}
if ($currency == "Canadian Dollar"){
$convamount = $amount * $canadarate;
$convamount = round($convamount, 2);
echo"<b>$amount</b> US Dollars is approximately equal to <b>$convamount</b> Canadian Dollars.";
}
if ($currency == "Australian Dollar"){
$convamount = $amount * $ausrate;
$convamount = round($convamount, 2);
echo"<b>$amount</b> US Dollars is approximately equal to <b>$convamount</b> Australian Dollars.";
}
?>
<br><br>
<i>Please note, that the exchange rates are updated manually, and may not be precisely accurate.</i>

</p>

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

(The echos for $currency_data[$i]["name"]; and so on are just so I can check the calls are working.)

What I need to do is get the values for $eurorate, $poundrate, $canadarate and $ausrate from the XML file. I'm sure it's relatively simple, but I can't find anywhere that tells me where to do it.

Can anyone rescue me?

Thanks and best wishes,
Rupe .


Rupe Parnell
www.starsol.co.uk
__________________
Rupe Parnell
www.starsol.co.uk
  #2 (permalink)  
Old July 16th, 2003, 01:52 PM
Friend of Wrox
Points: 2,570, Level: 21
Points: 2,570, Level: 21 Points: 2,570, Level: 21 Points: 2,570, Level: 21
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Jun 2003
Location: San Diego, CA, USA
Posts: 836
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Well, the your problem is that you're unnecessarily obfuscating things by adding an array index ($i) that you don't need. If you would like to access currencies by their country, then the country itself should be the index into the array in which you store the currencies.

Here's your code, rewritten to reflect these changes:
Code:
<p align="center">
<b>[u]
Currency Converter
</u></b>
</p>

<p align="left">

<?php

function printr(&$var, $desc = '')
{
   echo '<pre>';
   if($desc != '') echo "$desc: ";
   print_r($var);
   echo "</pre>\n";
}

if(!($data = file_get_contents("currency_ex.xml")))
{
    die("Unable to open XML file.");
}

$curr_nation   = '';
$currency_data = array();
$tag_stack     = array();

function startElementHandler($parser, $name, $attrs)
{
    global $curr_nation;
    global $tag_stack;

    array_push($tag_stack, $name); // push onto the stack.

    if($name == "CURRENCY")
    {
        $curr_nation = $attrs["NATION"];
    }
}

function endElementHandler($parser, $element_name)
{
    global $tag_stack;
    array_pop($tag_stack);
}

function characterDataHandler($parser, $data)
{
    global $curr_nation;
    global $currency_data;
    global $tag_stack;

    $curr_tag = $tag_stack[count($tag_stack)-1];
    if($curr_tag == "NAME")
    {
        $currency_data[$curr_nation]["name"] = $data;
    }
    else if($curr_tag == "RATE")
    {
        $currency_data[$curr_nation]["rate"] = $data;
    }
}

if( !($xml_parser = xml_parser_create()) )
{
    die("Couldn't create XML parser.");
}

xml_set_element_handler($xml_parser, "startElementHandler", "endElementHandler");
xml_set_character_data_handler($xml_parser, "characterDataHandler");
xml_parse($xml_parser, $data, true);
xml_parser_free($xml_parser);

printr($currency_data, '$currency_data after parsing XML');

$amount = (isset($_GET['amount']))? $_GET['amount'] : 50;
foreach($currency_data as $nation => $data)
{
    echo "Country <i>$nation</i>. "
       . "Currency <i>$data[name]</i>. "
       . "Rate <i>$data[rate]</i>.\n";

    $convamount = round($amount * $data['rate'], 2);
    echo "<b>$amount</b> US Dollars is approximately equal to "
       . "<b>$convamount</b> {$data['name']}s.<br/>\n";
}
?>
<br><br>
<i>Please note, that the exchange rates are updated manually,
          and may not be precisely accurate.</i>

</p>
New -- I'm using file_get_contents() to read the file data, not messing with file pointers, fopen(), fread(), and feof().

Also -- I'm using a stack to keep track of which tag we're in, not a single string. I ditched your tag counter. I added a useful debugging function, printr(), to display the contents of the array after parsing.

I assume that $amount is 50, unless you pass in a new amount as a GET paramater.

Hope it helps!


Take care,

Nik
http://www.bigaction.org/
  #3 (permalink)  
Old July 18th, 2003, 10:27 AM
Authorized User
 
Join Date: Jun 2003
Location: Kings Lynn, Norfolk, United Kingdom.
Posts: 10
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via ICQ to starsol
Default

Thanks Nik :) everything is working smoothly now.

Just a note to anyone reading this topic, the function file_get_contents requires PHP version 4.3.0 or higher.

There is a workaround in the note section for those running earlier versions on the official PHP website:
http://uk2.php.net/manual/en/functio...t-contents.php

Rupe Parnell
www.starsol.co.uk


Similar Threads
Thread Thread Starter Forum Replies Last Post
chapter 14 vthunder70 BOOK: Beginning ASP.NET 2.0 and Databases 2 October 3rd, 2007 02:11 PM
Chapter 14 example pkumar@ech BOOK: Professional Jakarta Struts 0 November 15th, 2006 09:10 AM
Chapter 14 JonG BOOK: Beginning Visual Basic 2005 Databases ISBN: 978-0-7645-8894-5 1 March 21st, 2006 10:04 PM
Chapter 14 Mike Smith BOOK: Professional C#, 2nd and 3rd Editions 2 January 4th, 2004 05:13 PM
C#: Chapter 14 - Exercise 3 Tchami BOOK: Beginning ASP.NET 1.0 0 November 26th, 2003 02:48 PM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.