Showing posts with label JSON. Show all posts
Showing posts with label JSON. Show all posts

Sunday, September 8, 2013

Parsing JSON with keys that have the at sign or @ symbol

I had to work with this interesting JSON file which had a metadata section which can be accessed with @metadata key. Here's a small sample of the JSON file:

 "twitter_handle": "..........",
 "website": ".............",
 "@metadata": {
  "Access-Control-Allow-Credentials": "true",
  "Raven-Entity-Name": "4fff7413",
  "@id": "4fff7413-f1bd-4e00-ab51-6754f1111c03",
  "Last-Modified": "2013-09-08T08:29:35.2587326Z",
  "Raven-Last-Modified": "2013-09-08T08:29:35.2587326",
  "@etag": "01000000-0000-0003-0000-000000000001",
  "Non-Authoritative-Information": false
 }

The twitter_handle or the website data are just normal JSON values so they are not that interesting but the @metadata is where it gets interesting. How do you access that?

At first I tried object.@metadata, didn't work. So I tried the next one which is object[@metadata] which also didn't work. I then found out over at StackOverflow that I was quite near. All I had to do was put single quotes so it would look like object['@metadata'].

It also works if you're trying to get a value inside, like say @id within @metadata. It would end up looking like object['@metadata']['@id'].


Wednesday, April 18, 2012

Getting knocked around while dealing with a check box

I've been using Knockoutjs heavily these couple of weeks and I think it has place in my programming toolkit. With Knockout, my markup is significantly cleaner and my pages with form elements are not a pain.

Knockout isn't that hard to use. I bet you can get a good handle of it once you finish some of the tutorials. Knockout, also has a couple of cool extensions like combining it with Kendo. I got good with Knockout but I had stuff to learn.

I had to implement a feature where an "admin" can select a "role" for new accounts. To select a role, admin had to select one of three check boxes in the page. The data for the check boxes is from JSON. Not a big problem since Knockout plays nice with jQuery.

So what exactly is the problem then?

The problem was that I needed to capture the "checked" value and push it into a new array. You would think that this a straight-forward preposition. So my first attempt went something like:

My Knockout script
<script type="text/javascript"> 
...{some code omitted for clarity}
        function roleModel(id, name, description) {
            var self = this;
            self.RoleId = id;
            self.RoleName = name;
            self.Description = description;
        }

        function viewModel(){
            var self = this;
            self.AvailableRoles = ko.observableArray();
            $.getJSON("/Role/GetRoles", function (data) {
                for (var i = 0; i < data.length; i++) {
                    self.AvailableRoles.push(new roleModel(data[i].RoleId, data[i].RoleName, data[i].Description));
                }
            });
            self.Roles = ko.observableArray();
        }
...{some code omitted for clarity}

        ko.applyBindings(new viewModel());

My Markup (HTML5)
<div data-bind="foreach: AvailableRoles">  
    <input type="checkbox" data-bind="attr: {value: AvailableRoles}, checked: Roles"/>  
    <span data-bind="text: RoleName"></span>  
</div>  
Notice the Roles and AvailableRoles properties. Apparently you can't bind the AvailbleRoles "directly" into the value field of the checkbox.

After looking around the web, I hit on the that idea I needed an intermediary field to store a key (thus I can bind it into the checkbox's value field) then I can use that key to retrieve the right role object from the AvailableRole object which is an array of role objects and store it in the Role property.
            
            self.Roles = ko.computed(function () {
                return ko.utils.arrayMap(self.SelectedRolesIds(), function (roleId) {
                    return ko.utils.arrayFirst(self.AvailableRoles(), function (item) {
                        return item.RoleId == roleId;
                    });
                });
            });
            self.SelectedRolesIds = ko.observableArray();
That's the SelectedRolesIds property in my viewModel. I also changed the Roles propety to be a computed field to make it "dependent" on what Role Ids are present in the SelectedRolesIds property. You still have to make changes to the markup. This all made nice with knockout utility functions - arrayMap and arrayFirst.

<div data-bind="foreach: AvailableRoles">  
    <input type="checkbox" data-bind="attr: {value: RoleId}, checked:$root.SelectedRolesIds"/>  
    <span data-bind="text: RoleName"></span>  
 </div>
The AvailableRoles property stays the same. 

Tuesday, August 30, 2011

Embedding Images to a Tapestry5 page very easily

OK I'll admit that the title might be problem but then again that's up to you.

Here's the thing, adding dynamic images in Tapestry5 templates is pie. You can read up on it here. But that seems to be best way if you are dealing with a file system or uploaded files. But what if the source is JSON data and doesn't need to be manipulated? Where we'd rather just stick it in directly into the template and display it.

Apparently this is just as easy as pie. First off, I'm dealing with a Base64 string as representation of the image within the JSON data. The image format is JPG, by the way for the just curious. Fortunately, Firefox and Chrome like Base64 strings. Then we can basically do this.

<img src="data:image/jpg;base64,iVBORw0KGgoAAAANS..." />

So what we need then is a webservice that pulls the JSON, process it a bit and pass it into the template.

public interface ICustomerService {

    public JsonObject getCustomerFromWebService(String id);
    
    public Customer getCustomer(String id);
        
    public Map<String, String> getCustomerHistory(String id, String code);
}

The ICustomerService is quite straight-forward. The implementation is where it gets interesting.

//Don't forget to add this into Tapestry5's service registry using binder.bind()    
    @Inject
    private Messages messages;

    JsonSystem system = StandardConfig.createSystem();
    
    public Customer getCustomer(String id) {
        JsonObject obj = getCustomeFromWebService(id);
        Customer customer = new Customer();
        // various gets;
        // lets skip to the interesting parts
        customer.setPhotoB64(obj.getString("ImageB64"));
        return customer;
    }

    public JsonObject getCustomerFromWebService(String id) {
        StringBuilder url = new StringBuilder( messages.get("localhost.mywebservice") );
        url.append(id);
        JsonObject object = system.get(url.toString()).asObject();
        return object;
    }


The first thing here is getting the URL of my web service - which I'm hosting locally. My dilemma was how to do this not in code so if the web service URL changes, I don't have to recompile. My answer was to use the Tapestry5 global properties via the messages catalog. All Tapestry5 web applications have this properties file in the WEB-INF folder. All you need to do is just @Inject the org.apache.tapestry5.ioc.Messages object and then you have now access.

The next bit is using ItemScript. ItemScript is very good JSON toolkit. I think you have noticed that getting JSON data with ItemScript is quite easy. Just create a JsonSystem object and then supply the URL. You should then get a JsonObject which now you can parse for data.

The final parts is just basically now use the new service. We'll start with the Index.java file.

@Inject
    private ICustomerService iCustomerService;
    
    public Customer getCustomer(){
        //let's try out our web service
        return iCustomerService.getCustomer("2033405");
    }
.....


The Index.tml file is just as easy. Add this right after the ${message:greeting} line.

<p>Test Customer</p>
<p> ${Customer.firstname}, ${Customer.lastname}</p>
<img src="data:image/jpg;base64,${Customer.photoB64}" />


Here is a screenshot.
The guy in the image is Aristotle "yoyong" Ucab. He's the guy who wrote the web service.

I don't really know where the heck this photo was taken.

Anyway, have fun with this.

Sunday, October 31, 2010

JSON, Java, JSONSimple, Exposed Web services and all that jazz.

First off JSON is fun stuff and its everywhere. JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. Almost all web services when invoked return JSON data.

Here is a sample show JSON looks like:


There's even a 3 minute tutorial on how to understand it.

Once you understood what JSON is, then its time to do something with it. In my case, is to process (or parse) it using Java and taking the lazy way out, use a toolkit that somebody else wrote to parse it - JSONSimple.

The thing with JSONSimple is that it maps JSON stuff into Java Collections types like List and Map.
Here is another sample on how to use it:
 String s="[0,{\"1\":{\"2\":{\"3\":{\"4\":[5,{\"6\":7}]}}}}]";  
 Object obj=JSONValue.parse(s);  
 JSONArray array=(JSONArray)obj;  
 System.out.println("======the 2nd element of array======");  
 System.out.println(array.get(1));  
 System.out.println();  
           
 JSONObject obj2=(JSONObject)array.get(1);  
 System.out.println("======field \"1\"==========");  
 System.out.println(obj2.get("1"));       


See their website for more encoding and decoding examples using JSONSimple.