views:

248

answers:

3

I'm getting an xml file and want to get data from it. The source of the xml doesn't really matter but what I;ve got to get a certain field is:

tracks = xmlDoc.getElementsByTagName("track");
variable = tracks.item(i).childNodes.item(4).childNodes.item(0).nodeValue;

Now this works like a charm, EXCEPT when there is no value in the node. So if the structure is like this:

<xml>
 <one>
  <two>nodeValue</two>
 </one>
 <one>
  <two></two>
 </one>
</xml>

the widget will crash on the second 'one' node, because there is no value in the 'two' node. The console says:

TypeError: tracks.item(i).childNodes.item(4).childNodes.item(0) has no properties

Any ideas on how to get the widget to just see empty as an empty string (null, empty, or ""), instead of crashing? I'm guessing something along the lines of data, getValue(), text, or something else.

using

var track= xmlDoc.getElementsByTagName('track')[0];
var info= track.getElementsByTagName('artist')[0];
var value= info.firstChild? info.firstChild.data : '';

doesn't work and returns "TypeError: track has no properties". That's from the second line where artist is called.

+1  A: 

Test that the ‘two’ node has a child node before accessing its data.

childNodes.item(i) (or the JavaScript simple form childNodes[i]) should generally be avoided, it's a bit fragile relying on whitespace text nodes being in the exact expected place.

I'd do something like:

var tracks= xmlDoc.getElementsByTagName('track')[0];
var track= tracks.getElementsByTagName('one')[0];
var info= track.getElementsByTagName('two')[0];
var value= info.firstChild? info.firstChild.data : '';

(If you don't know the tagnames of ‘one’ and ‘two’ in advance, you could always use ‘getElementsByTagName('*')’ to get all elements, as long as you don't need to support IE5, where this doesn't work.)

An alternative to the last line is to use a method to read all the text inside the node, including any of its child nodes. This doesn't matter if the node only ever contains at most one Text node, but can be useful if the tree can get denormalised or contain EntityReferences or nested elements. Historically one had to write a recurse method to get this information, but these days most browsers support the DOM Level 3 textContent property and/or IE's innerText extension:

var value= info.textContent!==undefined? info.textContent : info.innerText;
bobince
how would I go and traverse the "var tracks= xmlDoc.getElementsByTagName('track')[0];" like I do in my code with "tracks.item(i)"
xaddict
var tracks= xmlDoc.getElementsByTagName('track'); for (var i= 0; i<tracks.length; i++) { var track= tracks[i]; ... }
bobince
A: 

without a dtd that allows a one element to contain an empty two element, you will have to parse and fiddle the text of your xml to get a document out of it.

Empty elements are like null values in databases- put in something, a "Nothing" or "0" value, a non breaking space, anything at all- or don't include the two element.

Maybe it could be an attribute of one, instead of an element in its own right. Attributes can have empty strings for values. Better than phantom elements .

kennebec
actually empty elements are very iomportant in XML. an empty element can be created in two ways: </element> and <element></element>I do not have the dtd or creation source of the xml that I use but to leave out empty xml elements would go against the idea of standard-fields per item
xaddict
A: 

Yahoo! Widgets does not implement all basic javascript functions needed to be able to use browser-code in a widget.

instead of using:

tracks = xmlDoc.getElementsByTagName("track");
variable = tracks.item(i).childNodes.item(4).childNodes.item(0).nodeValue;

to get values it's better to use Xpath with a direct conversion to string. When a string is empty in Yahoo! Widgets it doesn't give any faults, but returns the 'empty'. innerText and textContent (the basic javascript way in browsers, used alongside things like getElementsByTagName) are not fully (or not at all) implemented in the Yahoo! Widgets Engine and make it run slower and quite awfully react to xmlNodes and childNodes. an easy way however to traverse an xml Document structure is using 'evaluate' to get everything you need (including lists of nodes) from the xml.

After finding this out, my solution was to make everything a lot easier and less sensitive to faults and errors. Also I chose to put the objects in an array to make working with them easier.

            var entries = xmlDoc.evaluate("lfm/recenttracks/track");
      var length = entries.length;
      for(var i = 0; i &lt; length; i++) {
       var entry = entries.item(i);
       var obj = {
        artist: entry.evaluate("string(artist)"),
        name: entry.evaluate("string(name)"),
        url: entry.evaluate("string(url)"),
        image: entry.evaluate("string(image[@size='medium'])")
        };
       posts[i] = obj;
      }
xaddict