Question

I have created a website that contains that uses XML to drive some of its contents, for example, the current exchange rates as shown below.

enter image description here The website compares three exchange rates and I currently use a separate functions for each city that perform identical goals e.g. returning the current exchange rates.

The only difference between these functions are the positions of the item tag from the XML document that I request the data from.

  $exchange['rate'] = $xml->channel->item[15]->description;

Notice item[15] in the above array which provides access to the Euro currency. In the following, the USA currency is item[56] as below.

  $exchange['rate'] = $xml->channel->item[56]->description;

Any ideas if it is possible to combine the three functions into a single one to increase cohesion?

The function I use for accessing the Euro currency is:

<?php

function get_rate1(SimpleXMLElement $xml) {

    // Match numeric values before and after decimal place
    $exchange['rate'] = $xml->channel->item[15]->description;
    preg_match('/([0-9]+\.[0-9]+)/', $exchange['rate'], $matches);
    $rate = $matches[0];

    // Get currency type from title
    $title['rate'] = $xml->channel->item[15]->title;
    $title = explode('/', $title['rate']);
    $title = $title[0];

    echo $rate . ' ' . $title . '<br />';

    return $rate;
}

?>

The feed URL's are set in another configuration script called cityConfig.php

<?php

// City 1 //
$city1 = 'Paris';
$exchangeRate1 = '1 Euro';
$exchangeRate1RssUrl = 'http://themoneyconverter.com/rss-feed/EUR/rss.xml';

?>

Thanks in advance

Was it helpful?

Solution

How about you change the rate function to this:

<?php

function get_rate(SimpleXMLElement $xml, $id) {

    // Match numeric values before and after decimal place
    $exchange['rate'] = $xml->channel->item[$id]->description;
    preg_match('/([0-9]+\.[0-9]+)/', $exchange['rate'], $matches);
    $rate = $matches[0];

    // Get currency type from title
    $title['rate'] = $xml->channel->item[$id]->title;
    $title = explode('/', $title['rate']);
    $title = $title[0];

    echo $rate . ' ' . $title . '<br />';

    return $rate;
}

?>

Then you can call it like this instead:

$rate1 = get_rate($xml,15);
$rate2 = get_rate($xml,56);

OTHER TIPS

Try this on for size - it uses the three letter currency codes, and uses XPath to find them, doing away with those nasty indexes altogether. All you need to supply is the three letter code of the source currency, and the three letter code of the destination, or an array of destinations if you want to get more than one at once.

MODIFIED so that $dest is now optional. If only $source is supplied, return an array of all exchange rates.

function get_rate ($source, $dest = NULL) {

  // Make sure source currency is upper case
  $source = strtoupper($source);

  // Construct the source URL
  $url = "http://themoneyconverter.com/rss-feed/$source/rss.xml";

  // This will hold the results
  $result = array();

  // Fetch and parse the data
  if (!$xml = simplexml_load_file($url)) {
    return FALSE;
  }

  if ($dest === NULL) {

    // Get all <item> nodes and loop them
    foreach ($xml->xpath("//item") as $item) {

      // Find the code of this currency
      $currencyParts = explode('/', $item->title);

      // Get the value of this currency
      $result[$currencyParts[0]] = (preg_match('/([0-9]+\.[0-9]+)/', $item->description, $matches)) ? (float) $matches[0] : FALSE;

    }

  } else {

    // Loop the destination currencies
    foreach ((array) $dest as $currency) {

      // Make sure destination currencies are upper case
      $currency = strtoupper($currency);

      // Perform an XPath search for this currency
      $nodes = $xml->xpath("//item[title='$currency/$source']/description");

      // If we found the currency and could extract the value, add it to the
      // result array as a float
      $result[$currency] = (count($nodes) === 1 && preg_match('/([0-9]+\.[0-9]+)/', $nodes[0], $matches)) ? (float) $matches[0] : FALSE;

    }

  }

  // If only a single value was requested return it, otherwise return the array
  return (count($result) === 1) ? array_shift($result) : $result;

}

Example usage:

$result = get_rate('GBP', 'USD');
var_dump($result);
/*
  float(1.58014)
*/

$result = get_rate('GBP', array('USD', 'EUR'));
var_dump($result);
/*
  array(2) {
    ["USD"]=>
    float(1.58014)
    ["EUR"]=>
    float(1.20236)
  }
*/

$result = get_rate('GBP');
var_dump($result);
/*
  array(64) {
    ["AED"]=>
    float(5.80445)
    ["ARS"]=>
    float(6.85316)
    ["AUD"]=>
    float(1.47589)
    ["BBD"]=>
    float(3.16103)
    ["BHD"]=>
    float(0.59427)
    ["BOB"]=>
    float(10.92135)
    ["BRL"]=>
    float(2.72171)
    ["CAD"]=>
    float(1.57968)
    ["CHF"]=>
    float(1.44883)
    ["CLP"]=>
    float(759.35947)
    ["CNY"]=>
    float(9.96753)
    ["COP"]=>
    float(2840.97943)
    ["CZK"]=>
    float(30.15863)
    ["DKK"]=>
    float(8.97219)
    ["EGP"]=>
    float(9.53446)
    ["EUR"]=>
    float(1.20265)
    ["HKD"]=>
    float(12.24901)
    ["HUF"]=>
    float(350.91425)
    ["IDR"]=>
    float(14121.92063)
    ["ILS"]=>
    float(5.87877)
    ["INR"]=>
    float(77.48491)
    ["ISK"]=>
    float(194.46687)
    ["JMD"]=>
    float(136.31954)
    ["JOD"]=>
    float(1.12059)
    ["JPY"]=>
    float(120.36272)
    ["KES"]=>
    float(132.28924)
    ["KRW"]=>
    float(1763.3828)
    ["KWD"]=>
    float(0.43897)
    ["LBP"]=>
    float(2382.62959)
    ["LKR"]=>
    float(180.02093)
    ["LTL"]=>
    float(4.1525)
    ["LVL"]=>
    float(0.84522)
    ["MAD"]=>
    float(13.39206)
    ["MXN"]=>
    float(20.24582)
    ["MYR"]=>
    float(4.77078)
    ["NAD"]=>
    float(12.10631)
    ["NGN"]=>
    float(253.27781)
    ["NOK"]=>
    float(9.21948)
    ["NPR"]=>
    float(123.97585)
    ["NZD"]=>
    float(1.89597)
    ["OMR"]=>
    float(0.6077)
    ["PAB"]=>
    float(1.58052)
    ["PEN"]=>
    float(4.25316)
    ["PHP"]=>
    float(67.48803)
    ["PKR"]=>
    float(142.95779)
    ["PLN"]=>
    float(5.03909)
    ["QAR"]=>
    float(5.75308)
    ["RON"]=>
    float(5.23271)
    ["RUB"]=>
    float(47.73085)
    ["SAR"]=>
    float(5.92694)
    ["SEK"]=>
    float(10.66422)
    ["SGD"]=>
    float(1.96993)
    ["THB"]=>
    float(48.79218)
    ["TRY"]=>
    float(2.77931)
    ["TWD"]=>
    float(46.6742)
    ["UAH"]=>
    float(12.71293)
    ["USD"]=>
    float(1.58052)
    ["UYU"]=>
    float(30.74107)
    ["VEF"]=>
    float(6.79622)
    ["VND"]=>
    float(33119.73602)
    ["XAF"]=>
    float(788.88394)
    ["XCD"]=>
    float(4.2674)
    ["XOF"]=>
    float(788.88394)
    ["ZAR"]=>
    float(12.10631)
  }
*/

Since I can't comment yet...helk's answer is perfect - you could take it one step further and define some class constants or define()'d constants so you aren't dealing with hard to remember numbers in your code (remember, you may not be the only person who ever looks at this code - you know what 15 is, but Jr. Dev Newguy does not):

<?php

define('CURRENCY_USA', 56);
define('CURRENCY_EURO', 15);

// OR something like:
class CurrencyHelper
{
    const CURRENCY_USA = 56;
    const CURRENCY_EURO = 15;

    // of course, you could also define get_rate here too...
    public function __construct(SimpleXmlElement $xml)
    {
        $this->xml = $xml;
    }  

    public function get_rate($id)
    {
      // ... your code here
    }
}

// Or, define your get_rate as originally intended:

function get_rate(SimpleXMLElement $xml, $id) {

    // Match numeric values before and after decimal place
    $exchange['rate'] = $xml->channel->item[$id]->description;
    preg_match('/([0-9]+\.[0-9]+)/', $exchange['rate'], $matches);
    $rate = $matches[0];

    // Get currency type from title
    $title['rate'] = $xml->channel->item[$id]->title;
    $title = explode('/', $title['rate']);
    $title = $title[0];

    echo $rate . ' ' . $title . '<br />';

    return $rate;
}

// Finally:
echo get_rate($xml, CURRENCY_EURO); // define
echo get_rate($xml, CurrencyHelper::CURRENCY_USA; // class constant
$myCurr = new CurrencyHelper($xml);
$myCurr->get_rate(CurrencyHelper::CURRENCY_USA); // Over-oop'd solution : P

?>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top