0

Some of the XML nodes is not always present in the XML feed, like gate and status, causing my code to break. This is my code:

$( document ).ready(function() {
    $('#load_btn').click(function() {
        loadXMLDoc();
    });
});  

function loadXMLDoc() {

    $.ajax({
        url: "proxy.php",
        type: "POST",
        dataType: "xml",
        data: {
            address: "http://flydata.avinor.no/XmlFeed.asp?TimeFrom=1&TimeTo=7&airport=OSL&direction=D&lastUpdate=2016-04-12T15:03:00Z"
        },

    })

    .done(function (xml) {

        var flightXML = $(xml).find('flight');
        //console.log(flightXML);
        var output = "<table>";
        output += "<tr><th>Departue</th><th>Flight</th><th>To</th><th>Airline</th><th>Gate</th></tr>"
        for(i=0; i < flightXML.length; i++)
            {

                var line = "<tr>";
                var timeElement = flightXML[i].getElementsByTagName("schedule_time");
                var time = timeElement[0].firstChild.nodeValue;
                var idElement = flightXML[i].getElementsByTagName("flight_id");
                var id = idElement[0].firstChild.nodeValue;
                var toElement = flightXML[i].getElementsByTagName("airport");
                var to = toElement[0].firstChild.nodeValue;
                var airlineElement = flightXML[i].getElementsByTagName("airline");
                var airline = airlineElement[0].firstChild.nodeValue;
                var gateElement = flightXML[i].getElementsByTagName("gate");
                var gate = gateElement[0].firstChild.nodeValue;
                //var statusElement = flightXML[i].getElementsByTagName("status");
                //var status = statusElement[0].firstChild.nodeValue;  

                line += "<td>" + time + "</td><td>" + id + "</td><td>" + to + "</td><td>" + airline + "</td><td>" + gate + "</td>";
                line += "</tr>";
                output += line;
            }
        output += "</table>";
        document.getElementById("result").innerHTML = output;


    });
}

This is the XML structure:

<flight uniqueID="5819145">
  <airline>SK</airline>
  <flight_id>SK815</flight_id>
  <dom_int>I</dom_int>
  <schedule_time>2016-04-12T18:15:00Z</schedule_time>
  <arr_dep>D</arr_dep>
  <airport>LHR</airport>
  <check_in>7 8</check_in>
  <gate>F19</gate>
</flight>
<flight uniqueID="5818372">
  <airline>EW</airline>
  <flight_id>EW4197</flight_id>
  <dom_int>S</dom_int>
  <schedule_time>2016-04-12T18:15:00Z</schedule_time>
  <arr_dep>D</arr_dep>
  <airport>HAM</airport>
  <check_in>7</check_in>
  <status code="C"></status>
</flight>
<flight uniqueID="5818645">
  <airline>SK</airline>
  <flight_id>SK291</flight_id>
  <dom_int>D</dom_int>
  <schedule_time>2016-04-12T18:15:00Z</schedule_time>
  <arr_dep>D</arr_dep>
  <airport>BGO</airport>
  <check_in>7 8</check_in>
  <gate>A4</gate>
</flight>

How can I check for presence of these nodes, and if not present, insert a blank space (or whatever is needed for my code not to break)?

2 Answers 2

1

You should separate your concerns better. Resist the temptation to write a function that does everything.

First concern: Request proxying

Let's abstract the plumbing for a proxied request into a function, complete with URL parameters that we can pass as an object.

function proxy(url, params) {
    if (!params || typeof params !== "object") params = {};
    return $.ajax({
        type: "post",
        url: "proxy.php",
        data: {address: url + "?" + $.param(params)}
    });
}

Remember to set the Content-Type header in proxy.php equal to the content type of the target page.

Second concern: Getting data from the remote API

We want an array of flights, where each flight has the properties schedule_time, flight_id, airport, airline, gate.

On top of that we want to pass in the query parameters (TimeFrom, TimeTo, airport, direction, lastUpdate) in a structured way.

function getFlights(params) {
    return proxy("http://flydata.avinor.no/XmlFeed.asp", params).then(function (xml) {
        return $(xml).find('flight').map(function () {
            var $flight = $(this);
            return {
                schedule_time: $flight.find("schedule_time").text(),
                flight_id: $flight.find("flight_id").text(),
                airport: $flight.find("airport").text(),
                airline: $flight.find("airline").text(),
                gate: $flight.find("gate").text()
            };
        }).toArray();
    });
}

Using .then() allows us to determine the overall result of the Ajax request, in our case it will be no longer XML but an array of uniform objects (no matter whether certain elements were missing in the XML).

Third concern: rendering

We want to turn an array of flights into a table. I would recommend handlebars.js for HTML generation, but we can do it manually with jQuery as well:

function renderFlights(flights) {
    var $table = $("<table>");
    $table.append("<tr><th>Departue</th><th>Flight</th><th>To</th><th>Airline</th><th>Gate</th></tr>");
    $.each(flights, function (i, flight) {
        var $tr = $("<tr>").appendTo($table);
        $("<td>", {text: flight.schedule_time }).appendTo($tr);
        $("<td>", {text: flight.flight_id }).appendTo($tr);
        $("<td>", {text: flight.airport }).appendTo($tr);
        $("<td>", {text: flight.airline }).appendTo($tr);
        $("<td>", {text: flight.gate }).appendTo($tr);
    });
    return $table;
}

Building HTML this way is safer than concatenating strings. It protects you against cross-site scripting attacks and random breakage due to unexpected special characters in the text.

Fourth concern: User interface wire-up

Now we can bind a button click very easily like this:

$(function() {
    $('#load_btn').click(function () {
        getFlights({
            TimeFrom: 1,
            TimeTo: 7,
            airport: "OSL",
            direction: "D",
            lastUpdate: "2016-04-12T15:03:00Z"
        }).done(function (flights) {
            var $table = renderFlights(flights);
            $("#result").empty().append($table);
        });
    });
});  
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. I see I have a way to go in the JS world... I will for sure spend some time trying to digest this. It loads faster also. Where does the ajax call get the actual params from? The click event? Now I only need to find out how to convert all the departure times from utc to etc, and translate all the airport and airline codes into their corresponding names (also available in xml). I guess I can do it with some sort of lookup function? Again, thank you.
Yes, the parameters are passed down from the click handler. That's also the place where you can change them, for example by reading them from other inputs. For the airport codes you can re-use the proxy function. Write another function in the style of getFlights to process them. I strongly recommend moment.js to deal with time conversion, -arithmetic and - formatting. Set a few breakpoints in the various functions and step through the code line b line to help understanding all the things that happen.
0

Depending on where it blows up, this might work:

var gateElement = flightXML[i].getElementsByTagName("gate");
var gate = gateElement[0].firstChild.nodeValue || "Gate not available";

I can't remember offhand if that would work. Might have to do:

var gate = "Gate not available";
var gateElement = flightXML[i].getElementsByTagName("gate");
if(gateElement) gate = gateElement[0].firstChild.nodeValue;

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.