Dealing With XML

Until recently, I have only been dealing with API data that is in JSON (JavaScript Object Notation – pronounced like the name Jason) format. JSON looks like

[{"replayEventTypes[{"id":5,"name":"movies","displayName":"Watch"}],
"id":70,
"title":"Notification Testing I",
"date":"2017-05 26T00:00:00",
"startTime":"08:20",
"endTime":"20:00",
"description":"Testing to see if notifications work on IOS",
"extendedDescription":null,
"location":"Not Important",
"image":null}

It could not be easier to access various levels of the object by using the dot notation. To get the values of the properties inside your html, you just reference the property on the object by object-name.property. So, for example, <h1>event.endTime</h1>.

Recently, I had to process an XML API, and, not surprisingly access to the various properties is different than with JSON. XML stands for eXtensible Markup Language. It is similar to HTML except different. Its purpose is to transport data over the web (as opposed to being used for display as HTML is). I was accessing the API in order to allow someone doing data entry to look up an Arcade Game and populate fields related to that game with the values of properties from that API.

Here’s what a “real” example of XML looks like:

<Game> 
<id>2</id>
<GameTitle>Crysis</GameTitle> 
<Platform>PC</Platform>
<ReleaseDate>11/13/2007</ReleaseDate> 
<Overview>From the makers of Far Cry, Crysis offers FPS fans the best-looking, most highly-evolving gameplay, requiring the player to use adaptive tactics and total customization of weapons and armor to survive in dynamic, hostile environments including Zero-G. Earth, 2019. </Overview>
<ESRB>M - Mature</ESRB> <Genres><genre>Shooter</genre></Genres>
<Players>4+</Players>
<Co-op>No</Co-op>

Here is my function as written in the script section of a “create” View file in .NET/ MVC project.

 function fill_form(id) {
            $('#games-by-id').html('');
            $.ajax({
                url: 'http://cors-anywhere.herokuapp.com/http://thegamesdb.net/api/GetGame.php?id=' + id,
                type: 'GET',
                dataType: 'xml',
                success: function (data) {
                    var gameTitle = $(data).find('GameTitle').text(),
                        overview = $(data).find('Overview').text(),
                        releaseDate = $(data).find('ReleaseDate').text(),
                        developer = $(data).find('Developer').text(),
                        genre = $(data).find('genre').text(),
                        players = $(data).find('Players').text();
                    var tempReleaseDate = new Date(releaseDate);
                    var releaseYear = tempReleaseDate.getFullYear();
                    $('#GameTitle').val(gameTitle);
                    $('#Overview').val(overview);
                    $('#ReleaseDate').val(releaseYear);
                    $('#Developer').val(developer);
                    $('#Genre').val(genre);
                    $('#Players').val(players);
                },
                error: function (error) {
                    console.log(error);
                }
            })
        }

So, as you can see, using JQuery and an AJAX request, you need to pass in XML as the data type and pass that data or xml or whatever into your callback function. Then you need to “find” each XML tag in the “data” (or xml or whatever), assign it a variable, and then put that variable into the HTML, which I did using the ids on the attributes.

To load what I would consider an array of XML objects, you can simply look at “each” of them. Good old jQuery. If you don’t have one of the new libraries or frameworks, it sure beats Vanilla JavaScript. For example,

 success: function (data) {
                    $('Game', data).each(function () {
                        var id = $(this).find('id').text(),
                         gameTitle = $(this).find('GameTitle').text(),
                         releaseDate = $(this).find('ReleaseDate').text(),
                         platform = $(this).find('Platform').text();
                        $('#games-by-id').append('<li class="list-group-item"
id="game' + id + '"><span id="catspan' + id + '"></span>' 
+ gameTitle + '</br>' + releaseDate + ' ' + platform + '</li>');
                        $('#game' + id).click(function () { fill_form(id); });
                    })
                }, 

You may have also noticed that I need to make a CORS request here. I will have to address that in another blog post once I figure out how to run my own proxy server.

I read a lot of different posts with lots of different ways to access XML, including from the JQuery documentation, but this is the way that is working for me.

Advertisements

Refactored Push Notifications

In my last post, I described how we set up a local React Native Push Notification to run at a scheduled time. The push notification was configured on the App State Change — background to active and vice versa. By sending an id (on Android) the notification was configured once and sent at the correct time, but only if the user had changed the state of the App. In iOS, there is no ID parameter (as such — I will get to that later), so if a user changed the state (opened the app, put the app in the background) multiple times, the push notification would fire multiple times.

I got to thinking about it and decided on a better way to configure the notification. I was hung up on the idea of an event listener. In React, you really have to either have an event listener or a lifecycle event to change/ update/ set the state. I was pretty sure we did not want to configure the notifications with a button push. Except, we actually did.

The push notifications are for events that are favorited by the users. So, I did a Homer forehead slap (“doh”) and realized we could just configure the notifications on the button push to add the event to the favorites array. And, even better, I realized if someone unfavorited the event, we could now remove that notification.

Cray then figured out that for iOS, we can send in a userInfo object and send an id in as a property on that object; that way there is an id to add and remove on iOS for the push notification. And, we can still use the id string property for Android.

Now the push controller looks like this:

import React, {Component} from 'react';
import PushNotification from 'react-native-push-notification';

export default class PushController extends Component {
    ComponentDidMount() {
      PushNotification.configure({
      onNotification: function(notification) {
         console.log('NOTIFICATION:', notification);
         console.log('User Info:', userInfo);
      }
    });
  }

    render() {
      return null;
  }
}

In a separate file, we have this function call:


handleFavoriteButtonPress(item){

    if (item.isFavorite){

            this.props.removeFavorite(item.id);
          //  Alert.alert('Item has been removed from your schedule');
          let id = (item.id).toString();
          PushNotification.cancelLocalNotifications({
            id: id, //removes local notification when item has been unfavorited
          });
        }
          
          else {
            this.props.addFavorite(item.id);
            if(this.props.favorites.length =10 ? "-"+(favoriteDate.getMonth()+1) : "-0"+(favoriteDate.getMonth()+1);
            let favoriteDay  = (favoriteDate.getDate()+1) >=10 ? "-"+(favoriteDate.getDate()+1) : "-0"+(favoriteDate.getDate()+1);
            let fifteenMinutesUntil = new Date ( favoriteDate.getFullYear()+favoriteMonth+favoriteDay+"T"+item.startTime+ "-"+"03:45");
          
            let id = (item.id).toString(); 
            if( fifteenMinutesUntil >= Date.now()){
              PushNotification.localNotificationSchedule({
              id: id, //for Android
              userInfo: {id: id}, //for iOS
              message: item.title + ' will begin in 15 minutes',
              date: new Date(fifteenMinutesUntil),
           });} 
          }
    }

One thing you should know is that even to send local push notifications, you will need to get the permission from Apple to do so.

As quoted from their docs

For a provider to communicate with APNs, it must employ a valid authentication key certificate (for token-based connection trust) or SSL certificate (for certificate-based connection trust). You obtain either of these certificates from your online developer account, as explained in “Configure push notifications” in Xcode Help. To choose between the two certificate types, read Provider-to-APNs Connection Trust. Whichever certificate type you choose, provider connection trust is prerequisite to a provider sending push notification requests to APNs.

Hope this was helpful.