开发者

When JSONP data changes

开发者 https://www.devze.com 2023-03-17 05:06 出处:网络
UPDATE 1: I can get around the problem with a try/catch, but I would prefer not to use this method when I know what the problem is:

UPDATE 1:

I can get around the problem with a try/catch, but I would prefer not to use this method when I know what the problem is:

try {
    buildHTML.push( "<tr><td>" + day.td[0].div.abbr.content + "</td><td><img src='" + day.td[1].div.div.img.src + "' /></td><td>" + day.td[2].span[0].span.content + "</td><td>" + day.td[3].span[0].span.content + "</td><td>" + day.td[4].span[0].span[1].content + "</td>");
} catch(err) {
    buildHTML.push( "<tr><td>" + day.td[0].div.abbr.content + "</td><td><img src='" + day.td[1].div.div.img.src + "' /></td><td></td><td>" + day.td[3].span[0].span.content + "</td><td>" + day.td[4].span[0].span[1].content + "</td>");
}

ORIGINAL QUESTION:

Using the following jsonp service:

http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%20%3D%20%22http%3A%2F%2Fnews.bbc.co.uk%2Fweather%2Fforecast%2F4276%3F%26search%3Dgerrards%2520cross%26itemsPerPage%3D10%26region%3Dworld%26area%3DGerrards%2520Cross%22%20and%20xpath%3D'%2F%2Ftbody'&format=json&callback=cbfunc22

I use the following script to capture the data:

$(document).ready(function() {
    get_bbc_weather();

    function get_bbc_weather() {
        $.ajax({
            url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%20%3D%20%22http%3A%2F%2Fnews.bbc.co.uk%2Fweather%2Fforecast%2F4276%3F%26search%3Dgerrards%2520cross%26itemsPerPage%3D10%26region%3Dworld%26area%3DGerrards%2520Cross%22%20and%20xpath%3D'%2F%2Ftbody'&format=json&callback=cbfunc22&rand=" + Math.random(),
            type: 'GET',
            dataType: 'jsonp',
            jsonp: 'callback',
            jsonpCallback: 'cbfunc22',
            error: function(xhr, status, error) {
                alert(xhr.responseText);
            },
            success: function(data) { 
                var buildHTML = [];

                var weather = data.query.results.tbody.tr;

                buildHTML.push("<tr><td>Day</td><td>Weather</td><td>Max<br />Day<br />(°C)</td><td>Min<br />Night<br />(°C)</td><td>Wind<br />(MPH)</td>");

                for (var i = 0; i < weather.lengt开发者_JAVA百科h; i++) {
                    var day = weather[i];

                    buildHTML.push( "<tr><td>" + day.td[0].div.abbr.content + "</td><td><img src='" + day.td[1].div.div.img.src + "' /></td><td>" + day.td[2].span[0].span.content + "</td><td>" + day.td[3].span[0].span.content + "</td><td>" + day.td[4].span[0].span[1].content + "</td>");
                }

                $('#divContent1').empty().append("<table>" + buildHTML.join("</tr>") + "</table>")


            }
        });

    }

});

However, at a certain time of the day, day.td[2].span[0].span.content becomes null. When this happens, how do I detect it and use the next temp min section instead only for the first day? The rest of the days should continue to use the temp max section.


I may be stating the obvious here, but why not just use an if statement?

if (day.td[2].span[0].span.content != null) {
    buildHTML.push( "<tr><td>" + day.td[0].div.abbr.content + "</td><td><img src='" + day.td[1].div.div.img.src + "' /></td><td>" + day.td[2].span[0].span.content + "</td><td>" + day.td[3].span[0].span.content + "</td><td>" + day.td[4].span[0].span[1].content + "</td>");
} 
else {
    buildHTML.push( "<tr><td>" + day.td[0].div.abbr.content + "</td><td><img src='" + day.td[1].div.div.img.src + "' /></td><td></td><td>" + day.td[3].span[0].span.content + "</td><td>" + day.td[4].span[0].span[1].content + "</td>");
}


If you use the YQL console to examine the output you're getting, you'll see that the entire td becomes null. So that's why you're getting the error.

You should be doing:

if (day.td[2] == null)

(Or whichever way you fancy doing the conditional output.)

It just so happened that it was night in the UK when I looked at it, so I actually got the problematic output. But given that that page can find you a weather forecast for places around the world, you could just as easily pick a city in some other timezone and use that to test it.


To use the min temp from the same day, change this

day.td[2].span[0].span.content

to this

(day.td[2].span[0].span.content == null ? day.td[3].span[0].span.content : day.td[2].span[0].span.content)

If this still throws an exception, you need to figure out which part of day.td[2].span[0].span.content is returning empty, i.e. maybe you need to check for day.td[2].span[0] == null.

Edit: To be clear, your statement would look like this:

buildHTML.push( "<tr><td>" + day.td[0].div.abbr.content + "</td><td><img src='" + day.td[1].div.div.img.src + "' /></td><td>" + (day.td[2].span[0].span.content == null ? day.td[3].span[0].span.content : day.td[2].span[0].span.content) + "</td><td>" + day.td[3].span[0].span.content + "</td><td>" );

Also, if you just want that cell to be blank (instead of using the max temp), use this:

(day.td[2].span[0].span.content == null ? "" : day.td[2].span[0].span.content)


You can use the || opreator to replace the null value with another value. I'm not sure exactly what value you want, but this would use the value for the next day:

buildHTML.push(
  "<tr>" +
  "<td>" + day.td[0].div.abbr.content + "</td>" +
  "<td><img src='" + day.td[1].div.div.img.src + "' /></td>" +
  "<td>" + (day.td[2].span[0].span.content || weather[i+1].td[2].span[0].span.content) + "</td>" +
  "<td>" + day.td[3].span[0].span.content + "</td>" +
  "<td>" + day.td[4].span[0].span[1].content + "</td>"
);


As sJhonny mentioned, you just need to use an if statement. The catch is that you need to know what's actually null, because following a pointer anywhere past the null value is going to give you an error. Without knowing the particulars of the data you get back, you should just be able to check everything down the line:

var td2 = "";
if ( day.td[2] != null && day.td[2].span != null && day.td[2].span.length > 0 && day.td[2].span[0] != null && day.td[2].span[0].span != null && day.td[2].span[0].span.content != null ) {
    td2 = day.td[2].span[0].span.content;
}

buildHTML.push( "<tr><td>" + day.td[0].div.abbr.content + "</td><td><img src='" + day.td[1].div.div.img.src + "' /></td><td>" + td2 + "</td><td>" + day.td[3].span[0].span.content + "</td><td>" + day.td[4].span[0].span[1].content + "</td>");

Of course, if you know what field is specifically being set to null, you could simplify that if statement. I wouldn't be worried about using a try/catch, if that makes your code more legible (In this case, I think I prefer the try/catch, myself). Either way, you probably should be checking those other fields -- you can protect your site from random errors in the off chance that some other data field happens to be null in that feed.


I know this is a lot more than what you probably wanted, but it's truly the way I'd solve this problem.

Rather than getting JSON back from the web service, here I'd recommend getting HTML (example request) since you're using jQuery and it provides a nice search mechanism - as opposed to traversing the structure yourself and running into snags when that structure changes.

Here's my code to produce the same table you're making, in a structure-agnostic way. I've left out all the ajax parts since they'd stay the same. This is just the success handler.

function success(data) {

  var

    $data = $('<table></table>')
      .html(data.results[0]),

    $table = $(
      '<table>' +
        '<thead>' +
          '<tr>' +
            '<th>Day</th>' + 
            '<th>Weather</th>' + 
            '<th>Max<br />Day<br />(°C)</th>' + 
            '<th>Min<br />Night<br />(°C)</th>' + 
            '<th>Wind<br />(MPH)</th>' +
          '</tr>' +
        '</thead>' +
        '<tbody></tbody>' +
      '</table>'
    ),

    $tbody = $table.find('tbody');

  $data
    .find('tr')
    .each(function(index, tr){

      var

        $input = $(tr),
        $output = $('<tr></tr>')
          .appendTo($tbody),

        selectors = [
          '.slotname abbr',
          '.summary p',
          '.temp.max .cent',
          '.temp.min .cent',
          '.wind .mph'
        ],
        i = selectors.length,

        text,
        $cell;

      while (i--) {
        $('<td></td>')
          .text(
            $input
              .find(selectors[i])
              .text()
          )
          .prependTo($output);
      }

    });

  $('#divContent1')
    .empty()
    .append($table);

}

Hope this helps!

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号