XQuery Source — Searching Flickr Photos

Once you have logged in to the Photo Search demonstration, the Web server displays a page created by main.xquery. This section describes how DataDirect XQuery uses the Flickr Web service API to search for photos.


The Search Page

The Search page lets you

  • Search for photos using a keyword
  • Display a list of previously run searches
  • Execute a previously run search
  • Delete all previously run searches

This section focuses on the search function. Executing a previously run search is discussed in the following section.

The Keywords and Max hits fields have default values, but you can change them to whatever you like. For the purposes of this discussion, we'll use XQuery as the keyword, and 8 for the number of hits we want returned.

What Happens When You Click Search?

The Search button is part of a typical HTML form:

...
<input type="submit" id="button_search" value="Search"/>
...

where the onsubmit="Search()" script event that invokes the "Search()=" function, which in turn calls SearchInternal. Let's take a closer look at SearchInternal to see what it does.

The SearchInternal() Function in main.xquery

The SearchInternal() function in main.xquery is defined as follows:

function SearchInternal(login, keywords, maxHits){{
            EnableButtons(false);
            
            keywords = keywords.replace(/"/g, '');
            keywords = keywords.replace(/&gt;/g, '');
            keywords = keywords.replace(/&lt;/g, '');
            keywords = keywords.replace(/&amp;/g, '');
            
            document.getElementById("edit_keywords").value = keywords;
            document.getElementById("edit_maxHits").value = maxHits;
            document.getElementById("divResult").innerHTML = '<img src="throbber.gif"/>';
            xmlhttp = ajax_getphotos(login, keywords, maxHits, true, onreadystatechange);
        }}

After disabling the Search, Show me my queries, and Delete my queries buttons, the ajax_getphotos() function defined in ajax.js is called. Among other parameters, it passes the keywords and maxHits parameters.

function ajax_getphotos(login, keywords, maxHints, asynch, onreadystatechange)
{
  url = "getphotos.xquery?login=" + login + "&keywords=" + keywords + "&maxHits=" + maxHints;
  return ajax_xmlhttp("POST", url, asynch, onreadystatechange);
}

These parameters are used to build the URL for getphotos.xquery.

The getphotos.xquery Query

The getphotos.xquery is where we first see a reference to the the Flickr API (http://api.flickr.com/services/rest/):

import module namespace flickr = "http://api.flickr.com/services/rest/" at "flickr.xquery";
declare option ddtek:serialize "method=html";
declare variable $login as xs:string external;
declare variable $keywords as xs:string external;
declare variable $maxHits as xs:integer external;

for $photoid in flickr:flickr_search($keywords, 1, $maxHits, "original_format, geo")//photo/@id
return
let $url := flickr:photoURL($photoid, "small")
return
    <a href="{flickr:photoURL($photoid, 'medium')}" target="NewWindow">
        <img src="{$url}"/>
    </a>

It is in the XQuery module flickr.xquery that the flickr:flickr_search() and flickr:photoURL() functions called by getphotos.xquery are defined. Both of these functions rely on the Flickr API, which is exposed as a set of Web services. Let's take a closer look at flickr.xquery now.

The flickr.xquery XQuery Module

The flickr.xquery XQuery module defines numerous functions that serve as wrappers for these Flickr Web services. These functions invoke the Flickr Web services using the doc() function. The DataDirect XQuery ddtek:wscall() function is another way to invoke Web services, especially those implemented using the SOAP protocol. (To learn more about the ddtek:wscall() function, click here.)

The flickr:flickr_search() function builds the URL of the server hosting the Flickr photo search Web services; the search itself is executed using the values for the $keywords and $maxhits parameters passed from getphotos.xquery.

...
declare function flickr:flickr_search(
 $keyword as xs:string, $page as xs:integer, $per_page as xs:integer,
    $extras (:license, date_upload, date_taken, owner_name, icon_server, original_format, last_update, geo, tags, machine_tags:))
{
    let $url := concat(
            $flickr:flickr_base_url,
            "?method=flickr.photos.search",
            $flickr:flickr_api_key,
            concat("&amp;page=", $page),
            concat("&amp;per_page=", $per_page),
            concat("&amp;tags=", $keyword)
        )
    return doc($url)
};

...

Once the search is complete, the flickr:photoURL() function returns a URL for each photo matching the search terms. An example of this URL is commented in the example of the flickr:photoURL() function shown here:

...

declare
function flickr:photoURL($id as xs:string, $size as xs:string)
{
 (:
    http://farm{farm-id}.static.flickr.com/{server-id}/{id}_{secret}_[mstb].jpg
  :)


 let $postfix_size :=
        if( $size = "small") then '_s'
   else if( $size = "thumbnail") then '_t'
   else if( $size = "medium") then '_m'
   else if( $size = "large") then '_b'
   else if( $size = "original") then '_o'
   else ()
 return

 let $info := flickr:flickr_getInfo($id)/rsp/photo
 return
    concat("http://farm",$info/@farm,
                        ".static.flickr.com/",
                        $info/@server,"/",
                        $info/@id,"_",$info/@secret, $postfix_size, ".jpg")
};

...

Changes to the Search Page

If we look again at getphotos.xquery, we see that it returns a thumbnail version of the photo ("small"). This image, along with any others that match the search term (up to the Max hits defined by the user), are displayed in a table inserted by main.xquery when it revises the original search page.

When the user clicks a thumbnail, a new browser instance is launched to display a larger (medium-sized) rendering of the image:

...
for $photoid in flickr:flickr_search($keywords, 1, $maxHits, "original_format, geo")//photo/@id
return
let $url := flickr:photoURL($photoid, "small")
return
    <a href="{flickr:photoURL($photoid, 'medium')}" target="NewWindow">
        <img src="{$url}"/>
    </a>

...

In addition to the photo thumbnails that appear on the search page, the Search, Show me my queries, and Delete my queries buttons are again enabled. We'll take a look at how Show me my queries works next.


What's Next?

We've shown you how DataDirect XQuery can be used to invoke a Web service. We'll conclude this discussion of the Photo Search demonstration application with a look at how photo search queries can be retrieved from a relational database and run again.