JayData.org

Implementing an RSS provider and using the model binder class

Author: Viktor Lazar May 31st, 2012

, , ,


An RSS provider is a very simple use case to demonstrate how to implement a new custom provider and how to use the refactored model binder class. An RSS provider is read-only and not filterable or orderable. Just a plain simple getter which uses AJAX to download data and converts the raw XML data to typed JSON using the model binder.

Provider

Before we start to implement our provider we have to think about data types. RSS is a very simple data format and so it’s very easy to implement the $data.Entity and $data.EntityContext custom classes to use JayData.

A $data.RSS.RSSItem entity is very simple. No restrictions, no primary key, no computed field. The entity context is even more simple. It contains only an Items entity set of $data.RSS.RSSItem. Currently we don’t expose the channel information through the context (but using the model binder you can do that too).

A new provider always have to inherit from the $data.StorageProviderBase class. You have to extend this class using extend, a core function of the library. After declaring the new provider class, don’t forget to register the provider to be able to reference it at context initialization!

In the provider class the two most important functions are initializeStore and executeQuery. In our read-only example we don’t have any storage to initialize, so we just processing the callback function given to the initializeStore function.

Here you can see the constructor and the executeQuery implementation of the RSS provider:

In executeQuery – as the function name describes it perfectly – we have to execute the query composed by the developer. Because our RSS provider doesn’t support any query functions except toArray, forEach, toTemplate and toJQueryTemplate which are executor methods, we just requesting the raw data from the server using AJAX.

When our AJAX call succeeded, we use the new model binder which lives in the $data.ModelBinder class to transform the raw XML data to typed JSON. The model binder configuration is easy even to hand-write it and describes the new shape of the data perfectly. Read further to see it how!

Model binder

The refactored model binder class supports complex structure definitions and its easy to define the type or source of data. The class supports even CSS and XML selectors to define the scope of the data source.

The main use case is to define a JSON structure and define the type and fields of each structure level. In the RSS provider you can see an advanced use case of the model binder structure definition. Even at this level it is very easy read and to implement.

As you can see in the example above, all property descriptor of a model binder definition has been implemented as a special field which starts with a “$” sign. All fields which are not starts with the “$” sign will be mapped as data fields. The source can be defined as a string which points to the source field of the data scope or a complete descriptor object where you can define the type, the selector, the source – including XML attributes – and even the value of the field.

The most important property descriptor is the $type descriptor. With this descriptor you can define the type of the current scope. If the given type has any member definitions and the fields of the current scope doesn’t declare any custom types, the model binder resolves the type of the fields by the member definitions of the scope type.

The type of the root level in the example will be an Array. An Array is a special case where you have to work with items. To define the type and structure of the array items you have to use the $item property descriptor. It is exactly as a new scope in the definition.

The $selector property descriptor is used to select the source of the current scope. You can use JSON, CSS and XML selectors.

A JSON descriptor is a simple JSON path down on the hierarchy from the current scope. Don’t use any names which are not a direct child node of the current data scope, like “json:Article” when the current scope is already the Article object.

You can’t select an item of an array. To visit all items of an array, you have to select the array first and define the $item property descriptor of the array, like in the RSS provider example.

A CSS descriptor uses the native querySelector and querySelectorAll functions of the browser. So it behaves exactly like as written in the specification. The root of the selector will be the current data scope.

An XML descriptor uses currently the native CSS selectors too. You have to define the $source property descriptor to select the text content or an attribute as the data source.

For the text content you can use this:

or for the attribute value…

In the RSS provider we don’t used any primary keys, but the model binder supports this descriptor. If you define this descriptor the data will be referenced based on the primary key field (or fields). Here is a short example:

If an Article with the same primary key already exists in the result set, it will not be duplicated and it will be referenced only – not a new instance – if it’s a sub-item like in the example query below.

If you want to give a field a constant value, you have to use the $value property descriptor. If the value of this field is a function, it will be evaluated. So you can define here a function which returns a random number or increments a counter.

It can look a bit complex for the first time but it’s really easy to use if you catch the hang of it!


, , ,