Developer Console

Step 4: Categories Recipe: Query Parameters

Let's continue configuring the Categories recipe by populating the query and queryResultType parameters.

query Parameter

The syntax you use differs between JSON and XML. See the tab that is relevant to your feed:

JSON Feeds

The sample app in Fire App Builder reads from a generic LightCast media feed that uses a JSON format. The Categories recipe uses the following value for the query parameter to return a list of categories from your feed: $..categories[*]. This syntax is Jayway JsonPath syntax. Here's what the syntax means in this particular instance:

Query Syntax What It Matches
$ Specifies the root directory as the beginning of the search.
.. Indicates a recursive search in every directory and subdirectory of the root for matches.
categories[] Says to look for the named array called "categories".
* Matches any contents (wildcard).

Putting it all together: $..categories[*] Starts at the root ($), looks in every directory and subdirectory recursively for matches (..), and looks to match on a named array called categories, with any contents in the array (*).

You can test your queries using the Jayway JsonPath Evaluator.

With the sample app in Fire App Builder, if you run this query ($..categories[*]) against the default LightCast feed URL (http://www.lightcast.com/api/firetv/channels.php?app_id=249&app_key=gtn89uj3dsw&action=channels_videos), the result returns the category names as strings, like this:

[
   "Costa Rica Islands",
   "Costa Rica Underwater",
   "Costa Rica Islands",
   "Costa Rica Attractions",
   "Costa Rica Underwater",
   "Costa Rica Islands",
   "Costa Rica Attractions",
   "Costa Rica Underwater",
   "Costa Rica Islands",
   "Costa Rica Attractions",
   "Costa Rica Underwater",
   "Costa Rica Attractions",
   "Costa Rica Islands",
   "Costa Rica Underwater",
   "Costa Rica Attractions",
   "Costa Rica Islands",
   "Costa Rica Underwater",
   "Costa Rica Islands",
   ...
]

(Fire App Builder will remove duplicates from the query result.)

Here's another sample query constructed with Jayway JsonPath: $.node[?(@.type == 'item')]. This example query searches the JSON object starting at the root for a node key whose value is an array. Within that array, it checks each item's type value. If the value equals item, then it's a hit and will be returned as part of the result. See the Jayway JsonPath documentation for an explanation of the available operators and other examples.

XML Feeds

If your feed is XML, instead of using Jayway JsonPath, you must use XPath expressions to target the specific elements in your feed. XPath reduces your XML document into various items called "nodes." The XPath syntax targets the location of specific nodes.

Suppose your XML feed contains a structure like this:

<rss>
    <channel>
        <item>
        <title>Sample Title</title>
        <pubDate>Wed, 26 Oct 2016 20:34:22 PDT</pubDate>
        <link>https://example.com/myshow/episodes/110</link>
        <author>Sample Author name</author>
        <category>Technology</category>
        <category>Gadgets</category>
        </item>
    </channel>
</rss>

To get the categories in this feed, you would use this XPath expression:

//category/text()

The // looks recursively in all nodes for matches, no matter where those nodes are located in the hierarchy. category selects the category node, and text() selects the text from that node.

You can test this out using the XPath Tester/Evaluator. The response from the expression is as follows:

Text='Technology'
Text='Gadgets'

(You can ignore the Text= part. This is just part of the XPath Tester's display, not what was matched in the query.)

Here's another example of an XPath expression: /node/item[index]. The example query searches the XML object from node element for an item element that's value is an array. Within that array, it selects the element at position index.

Try copying your XML feed into the XPath Tester/Evaluator and selecting the categories using a similar syntax.

See XPath syntax and the examples section on XPath Examples for more details about XPath expressions.

Targeting Elements with Namespaces

To target elements with namespaces, such as <media:category> (as the Media RSS specification requires) or <itunes: category text="Apples"/> (as the iTunes RSS tags requires) in the query parameter for Fire App Builder, not all XPath expressions will work. The following two sections provide some guidance.

Media RSS Categories Example

Suppose your XML feed follows the Media RSS spec and looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
   <channel>
      <title>Sample MRSS Feed</title>
      <link>https://some-site.com/mrss.xml</link>
      <language>en-us</language>
      <description>MRSS Feed For Amazon Test</description>
      <atom:link href="https://some-site.com/mrss.xml" rel="self" type="application/rss+xml" />
      <item>
         <title>May 18, 2018 - Apples</title>
         <description>May 18, 2018. Apples are a delicious fruit. Watch this fun documentary about apple growing and making.</description>
         <pubDate>Thu, 31 May 2018 22:45:38 GMT</pubDate>
         <guid>https://some-site.com/apples.mp4</guid>
         <itunes:subtitle>May 18, 2018. Apples are a delicious fruit. Watch this fun documentary about apple growing and making.</itunes:subtitle>
         <media:category>Farming</media:category>
         <media:content url="https://some-site.com/apples.mp4" type="application/mp4" medium="video" duration="2610.688" isDefault="true">
            <media:title>May 18, 2018 - Apples</media:title>
            <media:description>May 18, 2018.  Apples are a delicious fruit. Watch this fun documentary about apple growing and making.</media:description>
            <media:thumbnail url="http://some-site.com/thumbnails/apples.jpg" height="393" width="699" />
         </media:content>
      </item>
      <item>
         <title>May 23, 2018 - Bananas</title>
         <description>May 23, 2018. Bananas are a bunch of fun. Watch this interesting documentary about how to grow bananas.</description>
         <pubDate>Thu, 31 May 2018 22:45:41 GMT</pubDate>
         <guid>https://sample-server..net/3024343431/2234305/2345/3024422184001_3473874.mpd</guid>
         <itunes:subtitle>May 23, 2018. Bananas are a bunch of fun. Watch this interesting documentary about how to grow bananas..</itunes:subtitle>
         <media:category>Lifestyle</media:category>
         <media:content url="https://some-site.com/bananas.mp4" type="application/mp4" medium="video" duration="2610.688" isDefault="true">
            <media:title>May 18, 2018 - Apples</media:title>
            <media:description>May 18, 2018. Bananas are a bunch of fun. Watch this interesting documentary about how to grow bananas.</media:description>
            <media:thumbnail url="http://some-site.com/thumbnails/bananas.jpg" height="393" width="699" />
         </media:content>
      </item>
   </channel>
</rss>

To target the <media:category> element, you cannot use this:

"query": "//item/media:category/text()"

Although this syntax will work in XPath Tester, Fire App Builder doesn't use the same XPath parser. Instead, you must use this syntax:

"query": "//*[name()='media:category']/text()"

This syntax is still standard XPath expression syntax. Here we use // to select any node (at any depth) matching the criteria. The * is a wildcard, matching any node. [name()='media:category'] selects elements that have this media:category name. text() gets the text of the element.

Note that this special syntax restriction with namespaces applies only to the query parameter. The matchList parameter (explained in the next step) doesn't use XPath expressions.

iTunes RSS Tags Example

Suppose your feed follows the iTunes RSS tags and looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:media="http://search.yahoo.com/mrss/" version="2.0" xml:base="http://www.nasa.gov/">
   <channel>
      <title>Sample 1</title>
      <description>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed tincidunt vehicula placerat. Nunc eget auctor leo. Donec vitae neque vehicula, fermentum risus et, scelerisque felis. </description>
      <link>http://www.example.org/</link>
      <itunes:subtitle>Quisque egestas nec metus ac ullamcorper. In a semper ex, vulputate pellentesque massa.</itunes:subtitle>
      <itunes:summary>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed tincidunt vehicula placerat. Nunc eget auctor leo. Donec vitae neque vehicula, fermentum risus et, scelerisque felis. </itunes:summary>
      <itunes:category text="Fruits" />
      <itunes:keywords>fruit, baskets, farms</itunes:keywords>
      <itunes:image href="https://www.example.org/images/somelogo.png" />
      <item>
         <title>Weekly News, August 11, 2018</title>
         <link>http://www.example.org/weeklynews/august-18-2018.html</link>
         <description>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed tincidunt vehicula placerat. Nunc eget auctor leo. Donec vitae neque vehicula, fermentum risus et, scelerisque felis. </description>
         <enclosure url="https://amzndevresources.com/fire-app-builder/media/bunny.mp4" length="44842035" type="video/mp4" />
         <guid isPermaLink="false">august-11-2018</guid>
         <pubDate>Sat, 11 Aug 2018 09:00 EDT</pubDate>
         <source url="http://example.org.rss">Example Video</source>
         <itunes:category text="Apples" />
         <itunes:image href="https://amzndevresources.com/fire-app-builder/media/card.png" />
      </item>     
      <item>
         <title>Weekly News, August 30, 2018</title>
         <link>http://www.example.org/weeklynews/august-18-2018.html</link>
         <description>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed tincidunt vehicula placerat. Nunc eget auctor leo. Donec vitae neque vehicula, fermentum risus et, scelerisque felis. </description>
         <enclosure url="https://amzndevresources.com/fire-app-builder/media/bunny.mp4" length="44842333" type="video/mp4" />
         <guid isPermaLink="false">august-12-2018</guid>
         <pubDate>Sat, 12 Aug 2018 09:00 EDT</pubDate>
         <source url="http://example.org.rss">Example Video</source>
         <itunes:category text="Oranges" />
         <itunes:image href="https://amzndevresources.com/fire-app-builder/media/card.png" />
      </item>  
   </channel>
</rss>

Note that with iTunes feeds, there's a general category for the feed (such as <itunes:category text="Fruits">) as well as categories for each item (<itunes:category text="Apples" />). When you target categories for your recipe, you want to target the categories for each item in the feed, not the general feed category itself.

To select <itunes:category text="Apples" />, you would use this in your Category recipe:

"query": "/rss/channel/item//*[name()='itunes:category']"

This will return more than just the category name. It will the entire category element:

<itunes:category xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" text="Apples"/>'
<itunes:category xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" text="Oranges"/>'

You can then use the matchList parameters in the recipe (described in the next step) to select the actual attribute. For example, the Categories recipe would look like this:

{
  "cooker": "DynamicParser",
  "format": "xml",
  "model": "com.amazon.android.model.content.ContentContainer",
  "translator": "ContentContainerTranslator",
  "modelType": "array",
  "query": "/rss/channel/item//*[name()='itunes:category']",
  "queryResultType": "[]$",
  "matchList": [
    "#attributes/text@mName"
  ],
  "keyDataType":"#attributes/text@keyDataPath"
}

queryResultType Parameter

Fire App Builder needs to take the result from the query parameter and convert it into a hashmap to process in a Java class. So the next parameter (queryResultType) is used to convert the result into an array of objects. In the sample Fire App Builder application, the value for queryResultType is as follows:

"queryResultType": "[]$",

In this case, the result from the query parameter is a list of strings. This syntax, []$, will convert these strings into a hashmap for processing.

If the result from your query parameter returns a list of strings, include the queryResultType parameter in your Categories recipe and set it equal to []$. If the query's result already an object (a map), omit this parameter altogether.

Next Steps

To finish up with the category recipe, you need to configure the matchlist and keyDataType parameters. Continue to the next step: Categories Recipe: Matchlist Parameters.


Last updated: Aug 03, 2018