View Full Version : Help parsing an XML file from the web
alex57
08-10-2009, 09:01 PM
Hello,
I am trying to get the values from the xml file seen at: http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml
I am just trying to get one value before I write code for all of them using the script below. The script in the head is from w3schools.com and is trying to parse the xml file but I am getting no luck with anything. I have been all over the web for help with this xml source but have found nothing to work from.
Im pretty sure I could work with this xml if I could just get it working and returning one value first.
Many thanks
<html>
<head>
<script language="javascript" type="text/javascript">
function loadXMLDoc(dname) {
var xmlDoc;
if (window.XMLHttpRequest) {
xmlDoc = new window.XMLHttpRequest();
xmlDoc.open("GET", dname, false);
xmlDoc.send("");
return xmlDoc.responseXML;
}
// IE 5 and IE 6
else if (ActiveXObject("Microsoft.XMLDOM")) {
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
xmlDoc.load(dname);
return xmlDoc;
}
alert("Error loading document");
return null;
}
</script>
</head>
<body>
<script type="text/javascript">
xmlDoc = loadXMLDoc("http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml");
var a = xmlDoc.getElementsByTagName("Cube")[0];
var currency = a.getElementsByTagName("Cube")[1].getAttribute("currency");
alert(currency);
</script>
</body>
</html>
ckeyrouz
08-10-2009, 10:04 PM
I do not think that you can call an external file using ajax it is prevented by scripting.
alex57
08-10-2009, 11:00 PM
are there any other ways I can parse and use this file then please?
ckeyrouz
08-10-2009, 11:17 PM
I think that the best way is that your server sided code opens a url connection to the server where the xml file is stored and retrieves it from there.
I do not know what server sided code you are using but I can help you if you use java.
alex57
08-10-2009, 11:36 PM
well i'm trying to use the xml values to make a currency type calculator on the client side using javascript and the DOM. I dont think server side would be suitable for this. I am using PHP for any server side scripting that I do.
ckeyrouz
08-10-2009, 11:45 PM
In fact if you open a URL connection using PHP you can retrieve the string value of the xml and then you can print it out using the echo command in php .
There is an example here on how to open a url connection to a certain url and read its content in php:
http://www.koders.com/php/fidBBC4BAAEC708FE6CC990BF3E0FE7523E6F931121.aspx?s=login
Name the file for example (xmlretrieve.php) and make your ajax call to the file xmlretrieve.php instead of
http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml
alex57
08-11-2009, 03:10 PM
Hello,
I see how that could work but im not sure how it will work in practice with the site im creating.
When I get home from work I will upload what I have to a webserver and give you the link, maybe you can see better what I am trying to achieve.
Thanks!
alex57
08-11-2009, 08:06 PM
Hello,
This is my site cut down to the basics. http://www.rtwpricetag.com/tester.php
It is a calculator using javascript. The totaling is not actually working on this live version but I hope this shows the problem a bit better.
From the XML file located at the link I posted yesterday I need to extract the currency rates and store them in javascript variables so they can be applied when the convert drop down box is changed.
Maybe the scripts you suggest below are capable of achieving this but I have very little knowledge of actually writing AJAX.
ckeyrouz
08-11-2009, 08:48 PM
First of all you have to write this class and put it somewhere in your code(I do not know php I just got it from koders):
<?php
// CURL or fopen of URLs
class URLConnection {
/**
* The url
*/
protected $url;
/**
* The cache contents of the url
*/
protected $contents;
/**
* Default constructor
*/
public function __construct($url) {
$this->url = $url;
}
/**
* 'Getters' to return contents and url
*/
public function getContents(){
$this->readAndCacheContents();
return $this->contents;
}
public function getUrl(){
return $this->url;
}
/**
* Reads and cache the contents of the url
*/
public function readAndCacheContents() {
if ( !empty($this->contents) ) {
return;
}
if ( function_exists('curl_init') ) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept-Charset: UTF-8;')); // lets hope for a UTF-8 version
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_USERAGENT, 'Cinnamon Statistics Engine/'. Cinnamon::getVersion());
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_MAXREDIRS, 2);
$this->contents = curl_exec($ch);
curl_close($ch);
} else {
$fh = fopen($this->url, 'rb');
if ( $fh ) {
$this->contents = stream_get_contents($fh);
fclose($fh);
}
}
}
}
?>
This class should be placed somewhere and give it a name URLConnection.php
This will be a common class that you will use whenever you need to get data from an external system.
After that you should create another php file named Currencies.php that uses the URLConnection.php and it should contain something like that:
<?php
header("Content-Type: text/xml");
include 'URLConnection.php';
$obj = new URLConnection('http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml');
echo $obj.getContents();
?>
Once done you use your method to call the ajax but for local file not external file as follows:
<html>
<head>
<script language="javascript" type="text/javascript">
function loadXMLDoc(dname) {
var xmlDoc;
if (window.XMLHttpRequest) {
xmlDoc = new window.XMLHttpRequest();
xmlDoc.open("GET", dname, false);
xmlDoc.send("");
return xmlDoc.responseXML;
}
// IE 5 and IE 6
else if (ActiveXObject("Microsoft.XMLDOM")) {
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
xmlDoc.load(dname);
return xmlDoc;
}
alert("Error loading document");
return null;
}
</script>
</head>
<body>
<script type="text/javascript">
xmlDoc = loadXMLDoc("make sure to put here the right path to the file...Currencies.php");
var a = xmlDoc.getElementsByTagName("Cube")[0];
var currency = a.getElementsByTagName("Cube")[1].getAttribute("currency");
alert(currency);
</script>
</body>
</html>
As I told you I do not know PHP but this what I have done in Java a similar example and I tried to translate it to PHP.
Give it a try
alex57
08-11-2009, 09:56 PM
hello,
I now have 3 files:
1) URLConnection.php - containing the class URLConnection
2) Currencies,php - contains the following piece of code. Note the inclusion of the class in URLConnection.php
<?php
header("Content-Type: text/xml");
include 'URLConnection.php';
$obj = new URLConnection('http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml');
echo $obj.getContents();
?>
3) Test.php - the AJAX call. The code I have is the same but note the xmldoc I am loading, I have inserted Currencies.php which I can only assume is correct. Anyway, I get no popup as the code invites and the screen is blank. I don't no if the error is with the AJAX call or with the DOM coding? What do you think?
<html>
<head>
<script language="javascript" type="text/javascript">
function loadXMLDoc(dname) {
var xmlDoc;
if (window.XMLHttpRequest) {
xmlDoc = new window.XMLHttpRequest();
xmlDoc.open("GET", dname, false);
xmlDoc.send("");
return xmlDoc.responseXML;
}
// IE 5 and IE 6
else if (ActiveXObject("Microsoft.XMLDOM")) {
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
xmlDoc.load(dname);
return xmlDoc;
}
alert("Error loading document");
return null;
}
</script>
</head>
<body>
<script type="text/javascript">
xmlDoc = loadXMLDoc("Currencies.php");
var a = xmlDoc.getElementsByTagName("Cube")[0];
var currency = a.getElementsByTagName("Cube")[1].getAttribute("currency");
alert(currency);
</script>
</body>
</html>
ckeyrouz
08-11-2009, 09:59 PM
As I told you I do not know PHP and I do not know if the syntax in the file currencies.php is correct.
Second you need to make sure that the include command in the file currencies.php points to a correct path.
once you verified both points above I want you to put these debugging messages in the test file:
after this:
xmlDoc = loadXMLDoc("Currencies.php");
put this:
alert(xmlDoc .xml);
alert(xmlDoc .parserError.reason);
alert(xmlDoc .parserError.srcText);
alex57
08-11-2009, 11:28 PM
hello,
Ok. I think the syntax in Currencies.php is correct:
<?php
//header("Content-Type: text/xml");
include 'URLConnection.php';
$obj = new URLConnection('http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml');
echo $obj;
echo "<br>";
echo $obj->getContents();
echo "<br>";
echo $obj->getURL();
echo "<br>";
echo $obj->readAndCacheContents();
?>
if I load this page I get the following printed to the browser:
Object id #1
Reference rates European Central Bank
http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml
this is a good sign because the second two lines can be seen in the file at http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml. However the readAndCacheContents() doesnt seem to return anything.
The include command path in Currencies.php is pointing to the correct place; all files are in the same folder.
I put the alerts in the test file but no alert messages appeared. Im not sure the call to Currencies.php is correct with:
xmlDoc = loadXMLDoc("Currencies.php");
what do you think? Do you know if that is a valid call.
thanks
ckeyrouz
08-12-2009, 05:04 AM
try changing this:
xmlDoc.open("GET", dname, false);
to this:
xmlDoc.open("POST", dname, false);
alex57
08-13-2009, 12:29 AM
I made the change but I still get no alert boxes to give info on any errors.
Thanks for all your help. Much appreciated. Any other methods of using this xml source or any further ideas on this method?
ckeyrouz
08-13-2009, 03:31 AM
can you check if the xml is well formed or not, so I need you to remove all the alert message and replace your js function with this one:
function loadXMLDoc(dname) {
var xmlDoc;
if (window.XMLHttpRequest) {
xmlDoc = new window.XMLHttpRequest();
xmlDoc.open("GET", dname, false);
xmlDoc.send("");
alert(xmlDoc.responseText);
return xmlDoc.responseXML;
}
// IE 5 and IE 6
else if (ActiveXObject("Microsoft.XMLDOM")) {
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
xmlDoc.load(dname);
alert(xmlDoc.responseText);
return xmlDoc;
}
alert("Error loading document");
return null;
}
By the way what browser you are using?
alex57
08-13-2009, 08:03 PM
Hello,
I replaced the function i had with the one you provided and the pop up appeared as at the link below.
http://www.rtwpricetag.com/print.jpg
This is the XML doc that is shown at the target URL (more or less, there seems to be a bit more writing). When I changed the call to this function by passing an incorrect parameter the pop up box showed a load of error writing. This is promising I think and says that the Currencies.php, and URLConnection.php files are doing their jobs.
Correct call with nice popup as seen on my web page:
xmlDoc = loadXMLDoc("Currencies.php");
Incorrect call which shows a lot of error writing:
xmlDoc = loadXMLDoc("rencies.php");
maybe the problem is that I am not using the correct coding to extract the XML data. do I need Xpath or can I use the DOM? Where do I go next?
Again, thanks for your assistance :)
ckeyrouz
08-13-2009, 09:22 PM
You javascript code is good I even tested it and it works fine.
The problem is that I see in your screen capture that your xml is not well formed and this is the reason behind it.
I reviewed your php code that is written and I found the problem.
You should replace this:
<?php
//header("Content-Type: text/xml");
include 'URLConnection.php';
$obj = new URLConnection('http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml');
echo $obj;
echo "<br>";
echo $obj->getContents();
echo "<br>";
echo $obj->getURL();
echo "<br>";
echo $obj->readAndCacheContents();
?>
with this:
<?php
header("Content-Type: text/xml");
include 'URLConnection.php';
$obj = new URLConnection('http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml');
echo $obj->getContents();
?>
You should only echo the content of the url connection not all the details and you should leave the content-type as text/xml.
anyway you are better than me in the php code.
alex57
08-14-2009, 12:10 AM
ah, so they source is rubbish. If the XML source is not well formed then there I should not continue with this. There are very few good sources out there though.
Why would a website publish a poorly formed source. I found another free source: http://www.bsi.si/_data/tecajnice/dtecbs.xml
Is the XML poorly formed too? The tags seem well nested. This is a new screenshot: http://www.rtwpricetag.com/print.jpg
ckeyrouz
08-14-2009, 05:02 AM
The XML is not well formed from the website it is well formed during its dispaly in the PHP file.
The content of the xml file can be read through the method:
echo $obj->getContents();
but writing all these values:
echo $obj;
echo "<br>";
echo $obj->getContents();
echo "<br>";
echo $obj->getURL();
echo "<br>";
echo $obj->readAndCacheContents();
will make the result a non well formed xml.
See the point?
ckeyrouz
08-14-2009, 06:29 AM
In order to use a well formed xml let this be your currencies.php file:
<?php
header("Content-Type: text/xml");
include 'URLConnection.php';
$obj = new URLConnection('http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml');
echo $obj->getContents();
?>
alex57
08-14-2009, 10:27 PM
hello,
I took the echos out before I ran the code. I'm working with these exact files:
Test.php - alert only shows the xml from the first screenshot, not the currency data from the file. This makes me believe I am not traversing the XML correctly. How can XML be traversed if it is a string? Or does loading the xml transform it into a traversable tree?
<html>
<head>
<script language="javascript" type="text/javascript">
function loadXMLDoc(dname) {
var xmlDoc;
if (window.XMLHttpRequest) {
xmlDoc = new window.XMLHttpRequest();
xmlDoc.open("GET", dname, false);
xmlDoc.send("");
alert(xmlDoc.responseText);
return xmlDoc.responseXML;
}
// IE 5 and IE 6
else if (ActiveXObject("Microsoft.XMLDOM")) {
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = false;
xmlDoc.load(dname);
alert(xmlDoc.responseText);
return xmlDoc;
}
alert("Error loading document");
return null;
}
</script>
</head>
<body>
<script type="text/javascript">
xmlDoc = loadXMLDoc("Currencies.php");
var a = xmlDoc.getElementsByTagName("Cube")[0];
var currency = a.getElementsByTagName("Cube")[1].getAttribute("currency");
alert(currency);
</script>
</body>
</html>
Currencies.php
<?php
header("Content-Type: text/xml");
include 'URLConnection.php';
$obj = new URLConnection('http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml');
echo $obj->getContents();
?>
URLConnection.php
<?php
// CURL or fopen of URLs
class URLConnection {
/**
* The url
*/
protected $url;
/**
* The cache contents of the url
*/
protected $contents;
/**
* Default constructor
*/
public function __construct($url) {
$this->url = $url;
}
/**
* 'Getters' to return contents and url
*/
public function getContents(){
$this->readAndCacheContents();
return $this->contents;
}
public function getUrl(){
return $this->url;
}
/**
* Reads and cache the contents of the url
*/
public function readAndCacheContents() {
if ( !empty($this->contents) ) {
return;
}
if ( function_exists('curl_init') ) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept-Charset: UTF-8;')); // lets hope for a UTF-8 version
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_USERAGENT, 'Cinnamon Statistics Engine/'. Cinnamon::getVersion());
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_MAXREDIRS, 2);
$this->contents = curl_exec($ch);
curl_close($ch);
} else {
$fh = fopen($this->url, 'rb');
if ( $fh ) {
$this->contents = stream_get_contents($fh);
fclose($fh);
}
}
}
}
?>
ckeyrouz
08-14-2009, 11:51 PM
When the xml is loaded it will transform the string into a traversable tree (your naming).
What I want you to do is to make sure that this syntax is correct:
header("Content-Type: text/xml");
if this does not work let your currencies.php become like this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?php
include 'URLConnection.php';
$obj = new URLConnection('http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml');
echo $obj->getContents();
?>
Make sure that there are no space and no blank lines before this line:
<?xml version="1.0" encoding="ISO-8859-1"?>
alex57
08-15-2009, 12:52 AM
hello,
I corrected this line:
header("Content-Type: text/xml");
to
header("Content-type: text/xml");
the capital 'T' is now lower case, but this had no different effect from before. I then added the:
<?xml version="1.0" encoding="ISO-8859-1"?>
and I got an error message reading to the effect of:
Parse error, unexpected T_STRING in Currencies.php on line 1
This is where this new piece of coding is.
ckeyrouz
08-16-2009, 09:11 PM
Since you corrected the PHP error now try removing this line:
<?xml version="1.0" encoding="ISO-8859-1"?>
and if it does not work try this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<?php
include 'URLConnection.php';
$obj = new URLConnection('http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml');
echo "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>";
echo $obj->getContents();
?>
alex57
08-19-2009, 12:38 AM
still nothing working. Removing:
<?xml version="1.0" encoding="ISO-8859-1"?>
gave me the xml in an alert message but my currency value didnt appear.
This gave the same T_STRING error
<?xml version="1.0" encoding="ISO-8859-1"?>
<?php
include 'URLConnection.php';
$obj = new URLConnection('http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml');
echo "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>";
echo $obj->getContents();
?>
ckeyrouz
08-19-2009, 12:45 AM
Now that the xml is loading, I found a bug in the javascript code after I checked the structure of the xml file you are loading.
change this in your code:
xmlDoc = loadXMLDoc("Currencies.php");
var a = xmlDoc.getElementsByTagName("Cube")[0];
var currency = a.getElementsByTagName("Cube")[1].getAttribute("currency");
alert(currency);
to this:
xmlDoc = loadXMLDoc("Currencies.php");
var a = xmlDoc.getElementsByTagName("Cube")[0];
var currency = a.getElementsByTagName("Cube")[0].getElementsByTagName("Cube")[0].getAttribute("currency");
in fact there are 3 levels of nodes named Cube as you can see in the file:
<Cube> // first level that you retrieving and assigning it to the variable a
<Cube time="2009-08-18"> // here you are getting the currency attribute but it does not contain
<Cube currency="USD" rate="1.4101"/> // you should go another level deep to begin reading the currency attribute
alex57
08-19-2009, 10:09 AM
Ah, good spot. I was thinking it must be my javascript because as you say, the xml seems to be loading ok. At work now so will have to test tonight. I hope thats the issue.
I have uploaded the three files im using to my webserver to test it in the last few days and the files that run with no T_STRING error gave me a cinnamon error. Im not sure why I got that or even what it is but im not worrying too much about that just yet, hope we can get it working first. Perhaps the correct javascript below will sort this.
If this works on my local machine, I will upload it to my webserver to test there and hopefully this cinnamon error will vanish. It may be a server configuration setting that is not right. I'll wait and see.
Thanks again.
ckeyrouz
08-19-2009, 04:23 PM
Keep us updated with the results.
alex57
08-20-2009, 12:37 AM
still no go. I made the change and the:
alert(currency);
didnt create any pop up. I think your coding is correct though. I agree with that.
alex57
08-20-2009, 12:51 PM
I found a way to parse the XML doc into a database. If I had a page which inserted the values into a DB and then had an AJAX call to a page to retrieve the database values would this be possible? Im not an AJAX man.
[PHP]
<?php
//This is a PHP (4/5) script example on how eurofxref-daily.xml can be parsed
//Read eurofxref-daily.xml file in memory
$XMLContent= file("http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml");
//the file is updated daily between 2.15 p.m. and 3.00 p.m. CET
foreach ($XMLContent as $line) {
if (ereg("currency='([[:alpha:]]+)'",$line,$currencyCode)) {
if (ereg("rate='([[:graph:]]+)'",$line,$rate)) {
//Output the value of 1 EUR for a currency code
echo '1 € = '.$rate[1].' '.$currencyCode[1].'<br />';
//--------------------------------------------------
// Here you can add your code for inserting
// $rate[1] and $currencyCode[1] into your database
//--------------------------------------------------
}
}
}
?>
[PHP]
alex57
08-20-2009, 12:54 PM
http://www.webmasterworld.com/php/3678518.htm
if you look at that webpage and scroll down to the post by COOPSTER at 7:19 pm on June 20, 2008 he talks about removing the namespace from the string and then his coding worked fine. I think I will try this tonight.
vBulletin® v3.8.2, Copyright ©2000-2010, Jelsoft Enterprises Ltd.