PDA

View Full Version : xml - JS array has no properties in FF?!



satelliteCoder
05-19-2008, 07:45 PM
Greetings,

I'm new to this forum, and am excited at the possiblity of reaching out to all of you for assistance. I of course, will assist others as well when i get the opportunity.

PROBLEM SYNOPISIS: My XML javascript code does not work properly in FireFox. I've been up and down this problem ... i've narrowed it down to the fact that when i getElementsByTagName("channel") the subsequent array has no properties.

Here is a basic version of what i'm working with:



<script language="javascript" type="text/javascript">
var browser
var xmlDoc
function browserDetect()
{
// code for IE
if (window.ActiveXObject)
{
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async=false;
xmlDoc.load("firefox.xml");
browser="ie";
testPhrase2();
}
else if (document.implementation && document.implementation.createDocument)
{
xmlDoc=document.implementation.createDocument("","",null);
xmlDoc.load("firefox.xml");
browser="ff";
var isLoaded = xmlDoc.load("firefox.xml");
if (isLoaded==true){testPhrase2();}
}
else
{
alert('Your browser cannot handle this script');
}
}

function testPhrase2(){
if (browser=="ie"){
var x=xmlDoc.getElementsByTagName("channel");
var channelName;
channelName=x[0].childNodes[0].childNodes[0].nodeValue;
document.getElementById(browser).innerHTML="This is an IE confirmation: "+ channelName;
}
else if (browser=="ff")
{
var x=xmlDoc.getElementsByTagName("channel");
var channelName;
channelName=x[0].childNodes[0].childNodes[0].nodeValue;
document.getElementById(browser).innerHTML="This is an FF confirmation: "+ channelName;
}
}
</script>


That's the basic javascript. It works fine in IE (of course) but fails in FireFox with the error console indicating "x[0] has no properties" - i guess i just don't understand how that is possible.

Below is the basix XML document used for this example:



<?xml version="1.0" encoding="iso-8859-1"?>
<channels>
<channel>
<name>XXX</name>
<status>YYY</status>
</channel>
<channel>
<name>ZZZ</name>
<status>YYY</status>
</channel>
</channels>


I've tried so many things ... i thought it was a whitespace issue (it's not), i thought it was a load delay issue (it is not) and now i'm simply out of ideas.

I humbly submit to anyone's help who is willing to assist.

Thank you in advance,
satelliteCoder

codeexploiter
05-20-2008, 12:07 PM
I've modified your code a bit so that it will run correctly in Firefox. I've highlighted all the modified lines in the respective functions below:

function browserDetect(){
// code for IE
if (window.ActiveXObject) {
xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async=false;
xmlDoc.load("ff.xml");
browser="ie";
testPhrase2();
}else if (document.implementation && document.implementation.createDocument) {
xmlDoc=document.implementation.createDocument("","",null);
xmlDoc.load("firefox.xml");
browser="ff";
xmlDoc.onload = testPhrase2;
}else{
alert('Your browser cannot handle this script');
}
}

function testPhrase2(){
if (browser=="ie"){
var x=xmlDoc.getElementsByTagName("channel");
var channelName;
channelName=x[0].childNodes[0].childNodes[0].nodeValue;
document.getElementById(browser).innerHTML="This is an IE confirmation: "+ channelName;
}else if (browser=="ff" && xmlDoc){
var x = xmlDoc.getElementsByTagName('channel');
document.getElementById(browser).innerHTML="";
for(var i = 0; i < x.length; i++){
var el = x[i];
var nmeEl = el.getElementsByTagName('name')[0];
if(nmeEl){
if(nmeEl.childNodes.length > 0)
document.getElementById(browser).innerHTML+= "This is an FF confirmation: "+ nmeEl.childNodes[0].nodeValue +"<br/>";
}
}
}
}


Please note that I haven't tested or touched the IE specific area as you were complaining a problem in FF. Here I've inserted all the values of the name field into the div element just for demonstration purpose. You can take whatever you want.

satelliteCoder
05-20-2008, 02:02 PM
Exploiter,

Thank you so much! The modified code you provided certainly works. But i'm not one to just take the solution and run with it ... i really want to understand why this works and what i did/was doing wrong. Allow me to express my understanding, and if you would confirm/correct me that would be great. (i will probably also ask a few questions)

1. In the else if statement you added the && xmlDoc - this is to ensure that the object has been initialized.

2. It is proper to set the innerHTML property to 'empty' prior to filling it with something.

3. You changed my double quotes to single quotes when using the getElement methods. I'm also assuming that this is proper (although i expect it could be preference). Are double quotes incorrect syntax?

4. Instead of accessing the X object as an array you looped through it with a for loop. Is it necessary to loop through the object array before you can access certain nodeValues? In my expanded application of this example i utilize the for loop, and it still doesn't work ... so i'm guessing my problems lays somewhere within the loop (NOTE i have not applied this new knowledge to the expanded app yet, but wil soon).

5. Within the for loop you simplified the process by setting certain values in variables - this step is preference and is not required.

6. I don't understand the reason for the following line:
var nameEl = el.getElementsByTagName('name')[0]; Why did you put the [0] in that statement?


Now i'd like to see if i can figure out where my problem was.

1. The DOM code i was using to access the X array was returning the 'x[0]' has no properties. Is my syntax incorrect? Or is the X object not really an array that can be accessed directly with that DOM, hence the need for a loop?



Your time and assistance is greatly appreciated. As you can see my drive, i'm not just looking for an answer but genuinely interested in learning the why of my errors.

Thanks again, i await your response.
satelliteCoder

codeexploiter
05-21-2008, 05:56 AM
1. In the else if statement you added the && xmlDoc - this is to ensure that the object has been initialized.
Correct

2. It is proper to set the innerHTML property to 'empty' prior to filling it with something.
In my example I just want to make sure that there are no items in the mentioned element. To make sure that I've emptied the element contents using innerHTML property, but this need not be in this manner all the time.

3. You changed my double quotes to single quotes when using the getElement methods. I'm also assuming that this is proper (although i expect it could be preference). Are double quotes incorrect syntax?
In JavaScript you can either use double or single quotes for representing Strings. In my case I use single quotes for representing them, you can use either of one.

1. The DOM code i was using to access the X array was returning the 'x[0]' has no properties. Is my syntax incorrect? Or is the X object not really an array that can be accessed directly with that DOM, hence the need for a loop?
IIn firefox it considered the line-break as an element and that alone broken your element accessing the you did in your code. In other words the number of element has increased and created an unexpected result.


4. Instead of accessing the X object as an array you looped through it with a for loop. Is it necessary to loop through the object array before you can access certain nodeValues? In my expanded application of this example i utilize the for loop, and it still doesn't work ... so i'm guessing my problems lays somewhere within the loop (NOTE i have not applied this new knowledge to the expanded app yet, but wil soon).

5. Within the for loop you simplified the process by setting certain values in variables - this step is preference and is not required.

6. I don't understand the reason for the following line:

var nameEl = el.getElementsByTagName('name')[0];

I'll answer all these questions 4,5 and 6 collectively.

Actually your problem can be solved in a number of different method need not be the method I've used here. I'll use another method here now:



function testPhrase2(){
if (window.ActiveXObject) {
var x = xmlDoc.getElementsByTagName("channel");
var channelName;
channelName = x[0].childNodes[0].childNodes[0].nodeValue;
document.getElementById('ie').innerHTML = "This is an IE confirmation: " + channelName;
}else if (document.implementation) {
var nameEls = xmlDoc.getElementsByTagName('name');
document.getElementById('ff').innerHTML = "";
for (var i = 0; i < nameEls.length; i++) {
if (nameEls[i]) {
if (nameEls[i].childNodes.length > 0)
document.getElementById('ff').innerHTML += "This is an FF confirmation: " + nameEls[i].childNodes[0].nodeValue + "<br/>";
}
}
}
}


In order to access the values stored in '<name>' element you don't have to use my initial method. You can checkout the above method in which I was accessing the '<channel>' element and access the '<name>' element from it, then access the text value stored in it from the '<name>' element. The new method is more simple as it directly access the '<name>' element and access their child node's node value.

getElementsByTagName is returns a node list with the given tag name, you can use this from any valid DOM object, Have a look at the following link to know more about this http://developer.mozilla.org/en/docs/DOM:element.getElementsByTagName

Hope this helps.